vincbeck commented on code in PR #70763:
URL: https://github.com/apache/airflow/pull/70763#discussion_r3750777502
##########
providers/amazon/src/airflow/providers/amazon/aws/operators/emr.py:
##########
@@ -1857,3 +1858,110 @@ def execute_complete(self, context: Context, event:
dict[str, Any] | None = None
if validated_event["status"] != "success":
raise AirflowException(f"Error deleting EMR Serverless
application: {validated_event}")
self.log.info("EMR serverless application %s deleted successfully",
self.application_id)
+
+
+class EmrServerlessStartSessionOperator(AwsBaseOperator[EmrServerlessHook]):
+ """
+ Start an EMR Serverless interactive session and wait until it is ready.
+
+ .. seealso::
+ For more information on how to use this operator, take a look at the
guide:
+ :ref:`howto/operator:EmrServerlessStartSessionOperator`
+
+ :param application_id: ID of the EMR Serverless application to run the
session on.
+ :param execution_role_arn: ARN of the IAM role the session assumes to
access data.
+ :param name: An optional name for the session.
+ :param idle_timeout_minutes: Auto-stop the session after this many idle
minutes.
+ :param configuration_overrides: Optional Spark/monitoring configuration
overrides.
+ :param wait_for_completion: If True, wait for the session to be ready
before returning.
+ :param aws_conn_id: The Airflow connection used for AWS credentials.
+ If this is ``None`` or empty then the default boto3 behaviour is used.
If
+ running Airflow in a distributed manner and aws_conn_id is None or
+ empty, then default boto3 configuration would be used (and must be
+ maintained on each worker node).
+ :param region_name: AWS region_name. If not specified then the default
boto3 behaviour is used.
+ :param verify: Whether or not to verify SSL certificates. See:
+
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html
+ :param waiter_max_attempts: Number of times the waiter should poll the
session to check the state.
+ :param waiter_delay: Number of seconds between polling the state of the
session.
+ :param deferrable: If True, the operator will wait asynchronously for the
session to be ready.
+ This implies waiting for completion. This mode requires aiobotocore
module to be installed.
+ (default: False, but can be overridden in config file by setting
default_deferrable to True)
+ """
+
+ aws_hook_class = EmrServerlessHook
+ template_fields: Sequence[str] = aws_template_fields(
+ "application_id",
+ "execution_role_arn",
+ "name",
+ "idle_timeout_minutes",
+ "configuration_overrides",
+ )
+
+ def __init__(
+ self,
+ *,
+ application_id: str,
+ execution_role_arn: str,
+ name: str | None = None,
+ idle_timeout_minutes: int | None = None,
+ configuration_overrides: dict | None = None,
+ wait_for_completion: bool = True,
+ waiter_delay: int = 10,
+ waiter_max_attempts: int = 60,
+ deferrable: bool = conf.getboolean("operators", "default_deferrable",
fallback=False),
+ **kwargs,
+ ):
+ super().__init__(**kwargs)
+ self.application_id = application_id
+ self.execution_role_arn = execution_role_arn
+ self.name = name
+ self.idle_timeout_minutes = idle_timeout_minutes
+ self.configuration_overrides = configuration_overrides
+ self.wait_for_completion = wait_for_completion
+ self.waiter_delay = waiter_delay
+ self.waiter_max_attempts = waiter_max_attempts
+ self.deferrable = deferrable
+
+ def execute(self, context: Context) -> dict:
+ session_id = self.hook.start_session(
+ application_id=self.application_id,
+ execution_role_arn=self.execution_role_arn,
+ name=self.name,
+ idle_timeout_minutes=self.idle_timeout_minutes,
+ configuration_overrides=self.configuration_overrides,
+ )
+ self.log.info("Started EMR Serverless session %s", session_id)
+
+ if self.deferrable:
+ self.defer(
+ trigger=EmrServerlessSessionTrigger(
+ application_id=self.application_id,
+ session_id=session_id,
+ waiter_delay=self.waiter_delay,
+ waiter_max_attempts=self.waiter_max_attempts,
+ aws_conn_id=self.aws_conn_id,
+ ),
+ timeout=timedelta(seconds=self.waiter_max_attempts *
self.waiter_delay),
+ method_name="execute_complete",
+ )
+
+ if self.wait_for_completion:
+ wait(
+ waiter=self.hook.get_waiter("serverless_session_ready"),
+ waiter_delay=self.waiter_delay,
+ waiter_max_attempts=self.waiter_max_attempts,
+ args={"applicationId": self.application_id, "sessionId":
session_id},
+ failure_message="EMR Serverless session failed to start",
+ status_message="EMR Serverless session status is",
+ status_args=["session.state", "session.stateDetails"],
+ )
+ return {"application_id": self.application_id, "session_id":
session_id}
+
+ def execute_complete(self, context: Context, event: dict[str, Any] | None
= None) -> dict:
+ validated_event = validate_execute_complete_event(event)
+
+ if validated_event["status"] != "success":
+ raise RuntimeError(f"Error starting EMR Serverless session:
{validated_event}")
+ self.log.info("EMR Serverless session %s started",
validated_event["session_id"])
+ return {"application_id": self.application_id, "session_id":
validated_event["session_id"]}
Review Comment:
`execute_complete` should use only values from the event. Using
`self.application_id` in `execute_complete` is wrong. You cannot assume thr
same machine/worker will run `execute` and `execute_complete`. Therefore, if
you init `EmrServerlessStartSessionOperator` with `application_id=random()`,
this will fail
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]