misc.python.materialize.zippy.mz_actions
1# Copyright Materialize, Inc. and contributors. All rights reserved. 2# 3# Use of this software is governed by the Business Source License 4# included in the LICENSE file at the root of this repository. 5# 6# As of the Change Date specified in that file, in accordance with 7# the Business Source License, use of this software will be governed 8# by the Apache License, Version 2.0. 9 10 11from materialize.mzcompose.composition import Composition 12from materialize.mzcompose.services.materialized import ( 13 LEADER_STATUS_HEALTHCHECK, 14 DeploymentStatus, 15 Materialized, 16) 17from materialize.zippy.balancerd_actions import restart_balancerd 18from materialize.zippy.balancerd_capabilities import BalancerdIsRunning 19from materialize.zippy.blob_store_capabilities import BlobStoreIsRunning 20from materialize.zippy.crdb_capabilities import CockroachIsRunning 21from materialize.zippy.framework import ( 22 Action, 23 Capability, 24 Mz0dtDeployBaseAction, 25 State, 26) 27from materialize.zippy.mz_capabilities import MzIsRunning 28from materialize.zippy.table_capabilities import TableExists 29from materialize.zippy.view_capabilities import ViewExists 30 31 32class MzStart(Action): 33 """Starts a Mz instance (all components are running in the same container).""" 34 35 @classmethod 36 def requires(cls) -> set[type[Capability]]: 37 return {CockroachIsRunning, BlobStoreIsRunning} 38 39 @classmethod 40 def incompatible_with(cls) -> set[type[Capability]]: 41 return {MzIsRunning} 42 43 def run(self, c: Composition, state: State) -> None: 44 print( 45 f"Starting Mz with additional_system_parameter_defaults = {state.additional_system_parameter_defaults}" 46 ) 47 48 with c.override( 49 Materialized( 50 name=state.mz_service, 51 external_blob_store=True, 52 blob_store_is_azure=c.blob_store() == "azurite", 53 external_metadata_store=True, 54 deploy_generation=state.deploy_generation, 55 system_parameter_defaults=state.system_parameter_defaults, 56 sanity_restart=False, 57 restart="on-failure", 58 additional_system_parameter_defaults=state.additional_system_parameter_defaults, 59 metadata_store="cockroach", 60 default_replication_factor=2, 61 ) 62 ): 63 c.up(state.mz_service) 64 65 for config_param in [ 66 "max_tables", 67 "max_sources", 68 "max_objects_per_schema", 69 "max_materialized_views", 70 "max_sinks", 71 ]: 72 c.sql( 73 f"ALTER SYSTEM SET {config_param} TO 1000", 74 user="mz_system", 75 port=6877, 76 print_statement=False, 77 service=state.mz_service, 78 ) 79 80 c.sql( 81 """ 82 ALTER CLUSTER quickstart SET (MANAGED = false); 83 """, 84 user="mz_system", 85 port=6877, 86 service=state.mz_service, 87 ) 88 89 # Make sure all eligible LIMIT queries use the PeekPersist optimization 90 c.sql( 91 "ALTER SYSTEM SET persist_fast_path_limit = 1000000000", 92 user="mz_system", 93 port=6877, 94 service=state.mz_service, 95 ) 96 97 def provides(self) -> list[Capability]: 98 return [MzIsRunning()] 99 100 101class MzStop(Action): 102 """Stops the entire Mz instance (all components are running in the same container).""" 103 104 @classmethod 105 def requires(cls) -> set[type[Capability]]: 106 # Technically speaking, we do not need balancerd to be up in order to kill Mz 107 # However, without this protection we frequently end up in a situation where 108 # both are down and Zippy enters a prolonged period of restarting one or the 109 # other and no other useful work can be performed in the meantime. 110 return {MzIsRunning, BalancerdIsRunning} 111 112 def run(self, c: Composition, state: State) -> None: 113 c.kill(state.mz_service) 114 115 def withholds(self) -> set[type[Capability]]: 116 return {MzIsRunning} 117 118 119class MzRestart(Action): 120 """Restarts the entire Mz instance (all components are running in the same container).""" 121 122 @classmethod 123 def requires(cls) -> set[type[Capability]]: 124 return {MzIsRunning} 125 126 def run(self, c: Composition, state: State) -> None: 127 with c.override( 128 Materialized( 129 name=state.mz_service, 130 external_blob_store=True, 131 blob_store_is_azure=c.blob_store() == "azurite", 132 external_metadata_store=True, 133 deploy_generation=state.deploy_generation, 134 system_parameter_defaults=state.system_parameter_defaults, 135 sanity_restart=False, 136 restart="on-failure", 137 additional_system_parameter_defaults=state.additional_system_parameter_defaults, 138 metadata_store="cockroach", 139 default_replication_factor=2, 140 ) 141 ): 142 c.kill(state.mz_service) 143 c.up(state.mz_service) 144 145 146class Mz0dtDeploy(Mz0dtDeployBaseAction): 147 """Switches Mz to a new deployment using 0dt.""" 148 149 @classmethod 150 def requires(cls) -> set[type[Capability]]: 151 return {MzIsRunning} 152 153 def run(self, c: Composition, state: State) -> None: 154 state.deploy_generation += 1 155 156 state.mz_service = ( 157 "materialized" if state.deploy_generation % 2 == 0 else "materialized2" 158 ) 159 160 print(f"Deploying generation {state.deploy_generation} on {state.mz_service}") 161 162 with c.override( 163 Materialized( 164 name=state.mz_service, 165 external_blob_store=True, 166 blob_store_is_azure=c.blob_store() == "azurite", 167 external_metadata_store=True, 168 deploy_generation=state.deploy_generation, 169 system_parameter_defaults=state.system_parameter_defaults, 170 sanity_restart=False, 171 restart="on-failure", 172 healthcheck=LEADER_STATUS_HEALTHCHECK, 173 additional_system_parameter_defaults=state.additional_system_parameter_defaults, 174 metadata_store="cockroach", 175 default_replication_factor=2, 176 ), 177 ): 178 c.up(state.mz_service, detach=True) 179 c.await_mz_deployment_status( 180 DeploymentStatus.READY_TO_PROMOTE, state.mz_service 181 ) 182 c.promote_mz(state.mz_service) 183 c.await_mz_deployment_status(DeploymentStatus.IS_LEADER, state.mz_service) 184 c.stop( 185 ( 186 "materialized2" 187 if state.mz_service == "materialized" 188 else "materialized" 189 ), 190 wait=True, 191 ) 192 193 # Balancerd's resolver is fixed at startup and still points at the 194 # previous generation. Re-point it at the new leader. 195 if c.is_running("balancerd"): 196 restart_balancerd(c, state) 197 198 199class KillClusterd(Action): 200 """Kills the clusterd processes in the environmentd container. The process orchestrator will restart them.""" 201 202 @classmethod 203 def requires(cls) -> list[set[type[Capability]]]: 204 # Only kill once a dataflow-bearing object exists, so the kill has 205 # something to disrupt. 206 return [{MzIsRunning, ViewExists}, {MzIsRunning, TableExists}] 207 208 def run(self, c: Composition, state: State) -> None: 209 # Depending on the workload, clusterd may not be running, hence the || true 210 c.exec(state.mz_service, "bash", "-c", "kill -9 `pidof clusterd` || true")
33class MzStart(Action): 34 """Starts a Mz instance (all components are running in the same container).""" 35 36 @classmethod 37 def requires(cls) -> set[type[Capability]]: 38 return {CockroachIsRunning, BlobStoreIsRunning} 39 40 @classmethod 41 def incompatible_with(cls) -> set[type[Capability]]: 42 return {MzIsRunning} 43 44 def run(self, c: Composition, state: State) -> None: 45 print( 46 f"Starting Mz with additional_system_parameter_defaults = {state.additional_system_parameter_defaults}" 47 ) 48 49 with c.override( 50 Materialized( 51 name=state.mz_service, 52 external_blob_store=True, 53 blob_store_is_azure=c.blob_store() == "azurite", 54 external_metadata_store=True, 55 deploy_generation=state.deploy_generation, 56 system_parameter_defaults=state.system_parameter_defaults, 57 sanity_restart=False, 58 restart="on-failure", 59 additional_system_parameter_defaults=state.additional_system_parameter_defaults, 60 metadata_store="cockroach", 61 default_replication_factor=2, 62 ) 63 ): 64 c.up(state.mz_service) 65 66 for config_param in [ 67 "max_tables", 68 "max_sources", 69 "max_objects_per_schema", 70 "max_materialized_views", 71 "max_sinks", 72 ]: 73 c.sql( 74 f"ALTER SYSTEM SET {config_param} TO 1000", 75 user="mz_system", 76 port=6877, 77 print_statement=False, 78 service=state.mz_service, 79 ) 80 81 c.sql( 82 """ 83 ALTER CLUSTER quickstart SET (MANAGED = false); 84 """, 85 user="mz_system", 86 port=6877, 87 service=state.mz_service, 88 ) 89 90 # Make sure all eligible LIMIT queries use the PeekPersist optimization 91 c.sql( 92 "ALTER SYSTEM SET persist_fast_path_limit = 1000000000", 93 user="mz_system", 94 port=6877, 95 service=state.mz_service, 96 ) 97 98 def provides(self) -> list[Capability]: 99 return [MzIsRunning()]
Starts a Mz instance (all components are running in the same container).
36 @classmethod 37 def requires(cls) -> set[type[Capability]]: 38 return {CockroachIsRunning, BlobStoreIsRunning}
Compute the capability classes that this action requires.
The capability classes that this action is not compatible with.
44 def run(self, c: Composition, state: State) -> None: 45 print( 46 f"Starting Mz with additional_system_parameter_defaults = {state.additional_system_parameter_defaults}" 47 ) 48 49 with c.override( 50 Materialized( 51 name=state.mz_service, 52 external_blob_store=True, 53 blob_store_is_azure=c.blob_store() == "azurite", 54 external_metadata_store=True, 55 deploy_generation=state.deploy_generation, 56 system_parameter_defaults=state.system_parameter_defaults, 57 sanity_restart=False, 58 restart="on-failure", 59 additional_system_parameter_defaults=state.additional_system_parameter_defaults, 60 metadata_store="cockroach", 61 default_replication_factor=2, 62 ) 63 ): 64 c.up(state.mz_service) 65 66 for config_param in [ 67 "max_tables", 68 "max_sources", 69 "max_objects_per_schema", 70 "max_materialized_views", 71 "max_sinks", 72 ]: 73 c.sql( 74 f"ALTER SYSTEM SET {config_param} TO 1000", 75 user="mz_system", 76 port=6877, 77 print_statement=False, 78 service=state.mz_service, 79 ) 80 81 c.sql( 82 """ 83 ALTER CLUSTER quickstart SET (MANAGED = false); 84 """, 85 user="mz_system", 86 port=6877, 87 service=state.mz_service, 88 ) 89 90 # Make sure all eligible LIMIT queries use the PeekPersist optimization 91 c.sql( 92 "ALTER SYSTEM SET persist_fast_path_limit = 1000000000", 93 user="mz_system", 94 port=6877, 95 service=state.mz_service, 96 )
Run this action on the provided composition.
102class MzStop(Action): 103 """Stops the entire Mz instance (all components are running in the same container).""" 104 105 @classmethod 106 def requires(cls) -> set[type[Capability]]: 107 # Technically speaking, we do not need balancerd to be up in order to kill Mz 108 # However, without this protection we frequently end up in a situation where 109 # both are down and Zippy enters a prolonged period of restarting one or the 110 # other and no other useful work can be performed in the meantime. 111 return {MzIsRunning, BalancerdIsRunning} 112 113 def run(self, c: Composition, state: State) -> None: 114 c.kill(state.mz_service) 115 116 def withholds(self) -> set[type[Capability]]: 117 return {MzIsRunning}
Stops the entire Mz instance (all components are running in the same container).
105 @classmethod 106 def requires(cls) -> set[type[Capability]]: 107 # Technically speaking, we do not need balancerd to be up in order to kill Mz 108 # However, without this protection we frequently end up in a situation where 109 # both are down and Zippy enters a prolonged period of restarting one or the 110 # other and no other useful work can be performed in the meantime. 111 return {MzIsRunning, BalancerdIsRunning}
Compute the capability classes that this action requires.
120class MzRestart(Action): 121 """Restarts the entire Mz instance (all components are running in the same container).""" 122 123 @classmethod 124 def requires(cls) -> set[type[Capability]]: 125 return {MzIsRunning} 126 127 def run(self, c: Composition, state: State) -> None: 128 with c.override( 129 Materialized( 130 name=state.mz_service, 131 external_blob_store=True, 132 blob_store_is_azure=c.blob_store() == "azurite", 133 external_metadata_store=True, 134 deploy_generation=state.deploy_generation, 135 system_parameter_defaults=state.system_parameter_defaults, 136 sanity_restart=False, 137 restart="on-failure", 138 additional_system_parameter_defaults=state.additional_system_parameter_defaults, 139 metadata_store="cockroach", 140 default_replication_factor=2, 141 ) 142 ): 143 c.kill(state.mz_service) 144 c.up(state.mz_service)
Restarts the entire Mz instance (all components are running in the same container).
Compute the capability classes that this action requires.
127 def run(self, c: Composition, state: State) -> None: 128 with c.override( 129 Materialized( 130 name=state.mz_service, 131 external_blob_store=True, 132 blob_store_is_azure=c.blob_store() == "azurite", 133 external_metadata_store=True, 134 deploy_generation=state.deploy_generation, 135 system_parameter_defaults=state.system_parameter_defaults, 136 sanity_restart=False, 137 restart="on-failure", 138 additional_system_parameter_defaults=state.additional_system_parameter_defaults, 139 metadata_store="cockroach", 140 default_replication_factor=2, 141 ) 142 ): 143 c.kill(state.mz_service) 144 c.up(state.mz_service)
Run this action on the provided composition.
147class Mz0dtDeploy(Mz0dtDeployBaseAction): 148 """Switches Mz to a new deployment using 0dt.""" 149 150 @classmethod 151 def requires(cls) -> set[type[Capability]]: 152 return {MzIsRunning} 153 154 def run(self, c: Composition, state: State) -> None: 155 state.deploy_generation += 1 156 157 state.mz_service = ( 158 "materialized" if state.deploy_generation % 2 == 0 else "materialized2" 159 ) 160 161 print(f"Deploying generation {state.deploy_generation} on {state.mz_service}") 162 163 with c.override( 164 Materialized( 165 name=state.mz_service, 166 external_blob_store=True, 167 blob_store_is_azure=c.blob_store() == "azurite", 168 external_metadata_store=True, 169 deploy_generation=state.deploy_generation, 170 system_parameter_defaults=state.system_parameter_defaults, 171 sanity_restart=False, 172 restart="on-failure", 173 healthcheck=LEADER_STATUS_HEALTHCHECK, 174 additional_system_parameter_defaults=state.additional_system_parameter_defaults, 175 metadata_store="cockroach", 176 default_replication_factor=2, 177 ), 178 ): 179 c.up(state.mz_service, detach=True) 180 c.await_mz_deployment_status( 181 DeploymentStatus.READY_TO_PROMOTE, state.mz_service 182 ) 183 c.promote_mz(state.mz_service) 184 c.await_mz_deployment_status(DeploymentStatus.IS_LEADER, state.mz_service) 185 c.stop( 186 ( 187 "materialized2" 188 if state.mz_service == "materialized" 189 else "materialized" 190 ), 191 wait=True, 192 ) 193 194 # Balancerd's resolver is fixed at startup and still points at the 195 # previous generation. Re-point it at the new leader. 196 if c.is_running("balancerd"): 197 restart_balancerd(c, state)
Switches Mz to a new deployment using 0dt.
Compute the capability classes that this action requires.
154 def run(self, c: Composition, state: State) -> None: 155 state.deploy_generation += 1 156 157 state.mz_service = ( 158 "materialized" if state.deploy_generation % 2 == 0 else "materialized2" 159 ) 160 161 print(f"Deploying generation {state.deploy_generation} on {state.mz_service}") 162 163 with c.override( 164 Materialized( 165 name=state.mz_service, 166 external_blob_store=True, 167 blob_store_is_azure=c.blob_store() == "azurite", 168 external_metadata_store=True, 169 deploy_generation=state.deploy_generation, 170 system_parameter_defaults=state.system_parameter_defaults, 171 sanity_restart=False, 172 restart="on-failure", 173 healthcheck=LEADER_STATUS_HEALTHCHECK, 174 additional_system_parameter_defaults=state.additional_system_parameter_defaults, 175 metadata_store="cockroach", 176 default_replication_factor=2, 177 ), 178 ): 179 c.up(state.mz_service, detach=True) 180 c.await_mz_deployment_status( 181 DeploymentStatus.READY_TO_PROMOTE, state.mz_service 182 ) 183 c.promote_mz(state.mz_service) 184 c.await_mz_deployment_status(DeploymentStatus.IS_LEADER, state.mz_service) 185 c.stop( 186 ( 187 "materialized2" 188 if state.mz_service == "materialized" 189 else "materialized" 190 ), 191 wait=True, 192 ) 193 194 # Balancerd's resolver is fixed at startup and still points at the 195 # previous generation. Re-point it at the new leader. 196 if c.is_running("balancerd"): 197 restart_balancerd(c, state)
Run this action on the provided composition.
200class KillClusterd(Action): 201 """Kills the clusterd processes in the environmentd container. The process orchestrator will restart them.""" 202 203 @classmethod 204 def requires(cls) -> list[set[type[Capability]]]: 205 # Only kill once a dataflow-bearing object exists, so the kill has 206 # something to disrupt. 207 return [{MzIsRunning, ViewExists}, {MzIsRunning, TableExists}] 208 209 def run(self, c: Composition, state: State) -> None: 210 # Depending on the workload, clusterd may not be running, hence the || true 211 c.exec(state.mz_service, "bash", "-c", "kill -9 `pidof clusterd` || true")
Kills the clusterd processes in the environmentd container. The process orchestrator will restart them.
203 @classmethod 204 def requires(cls) -> list[set[type[Capability]]]: 205 # Only kill once a dataflow-bearing object exists, so the kill has 206 # something to disrupt. 207 return [{MzIsRunning, ViewExists}, {MzIsRunning, TableExists}]
Compute the capability classes that this action requires.
209 def run(self, c: Composition, state: State) -> None: 210 # Depending on the workload, clusterd may not be running, hence the || true 211 c.exec(state.mz_service, "bash", "-c", "kill -9 `pidof clusterd` || true")
Run this action on the provided composition.