| 228 | ) |
| 229 | |
| 230 | def wait_for_execute(self, stack_name, changeset_type): |
| 231 | sys.stdout.write("Waiting for stack create/update to complete\n") |
| 232 | sys.stdout.flush() |
| 233 | |
| 234 | # Pick the right waiter |
| 235 | if changeset_type == "CREATE": |
| 236 | waiter = self._client.get_waiter("stack_create_complete") |
| 237 | elif changeset_type == "UPDATE": |
| 238 | waiter = self._client.get_waiter("stack_update_complete") |
| 239 | else: |
| 240 | raise RuntimeError(f"Invalid changeset type {changeset_type}") |
| 241 | |
| 242 | # Poll every 30 seconds. Polling too frequently risks hitting rate limits |
| 243 | # on CloudFormation's DescribeStacks API |
| 244 | waiter_config = { |
| 245 | 'Delay': 30, |
| 246 | 'MaxAttempts': 120, |
| 247 | } |
| 248 | |
| 249 | try: |
| 250 | waiter.wait(StackName=stack_name, WaiterConfig=waiter_config) |
| 251 | except botocore.exceptions.WaiterError as ex: |
| 252 | LOG.debug("Execute changeset waiter exception", exc_info=ex) |
| 253 | |
| 254 | raise exceptions.DeployFailedError(stack_name=stack_name) |
| 255 | |
| 256 | def create_and_wait_for_changeset( |
| 257 | self, |