def lambda_task(func):
    """
    Decorator to make function run under zappa environment.
    Args:
        func (function): the function to be wrapped
    Further requirements:
        - func must be an independent top-level function.
            i.e. not a class method or an anonymous function
        - args & kwargs must be serializable
    Usage:
        @lambda_task
        def render(question_id):
            question.render()
        # You can call above function wherever you want;
        render(question_id=1)
        # and zappa task (which is actually AWS lambda function) will be invoked.
    """
    task_path = get_func_task_path(func)
    
    def _run_async(*args, **kwargs):
        """
        This is the wrapping async function that replaces the decorated function.
        Returns:
            The object returned includes state of the dispatch.
        """
        send_result = CustomLambdaAsyncResponse().send(task_path, args, kwargs)
        return send_result
    
    update_wrapper(_run_async, func)
    
    _run_async.service = 'lambda'
    _run_async.sync = func
    
    return _run_async
Exemple #2
0
    def test_async_call_with_defaults(self):
        """Change a task's asynchronousity at runtime."""
        # Import the task first to make sure it is decorated whilst the
        # environment is unpatched.
        async_me = import_and_get_task("tests.test_app.async_me")
        lambda_async_mock = mock.Mock()
        lambda_async_mock.return_value.send.return_value = "Running async!"
        with mock.patch.dict('zappa.async.ASYNC_CLASSES',
                             {'lambda': lambda_async_mock}):
            # First check that it still runs synchronously by default
            self.assertEqual(async_me("123"), "run async when on lambda 123")

            # Now patch the environment to make it look like we are running on
            # AWS Lambda
            options = {
                'AWS_LAMBDA_FUNCTION_NAME': 'MyLambda',
                'AWS_REGION': 'us-east-1'
            }
            with mock.patch.dict(os.environ, options):
                self.assertEqual(async_me("qux"), "Running async!")

        # And check the dispatching class got called correctly
        lambda_async_mock.assert_called_once_with(
            aws_region='us-east-1',
            capture_response=False,
            delay_seconds=0,
            lambda_function_name="MyLambda")
        lambda_async_mock.return_value.send.assert_called_with(
            get_func_task_path(async_me), ("qux", ), {})
Exemple #3
0
    def test_async_call_with_defaults(self):
        """Change a task's asynchronousity at runtime."""
        # Import the task first to make sure it is decorated whilst the
        # environment is unpatched.
        async_me = import_and_get_task("tests.test_app.async_me")
        lambda_async_mock = mock.Mock()
        lambda_async_mock.return_value.send.return_value = "Running async!"
        with mock.patch.dict('zappa.async.ASYNC_CLASSES',
                             {'lambda': lambda_async_mock}):
            # First check that it still runs synchronously by default
            self.assertEqual(async_me("123"),
                             "run async when on lambda 123")

            # Now patch the environment to make it look like we are running on
            # AWS Lambda
            options = {
                'AWS_LAMBDA_FUNCTION_NAME': 'MyLambda',
                'AWS_REGION': 'us-east-1'
            }
            with mock.patch.dict(os.environ, options):
                self.assertEqual(async_me("qux"),
                                 "Running async!")

        # And check the dispatching class got called correctly
        lambda_async_mock.assert_called_once()
        lambda_async_mock.assert_called_with(aws_region='us-east-1',
                                             capture_response=False,
                                             lambda_function_name="MyLambda")
        lambda_async_mock.return_value.send.assert_called_with(
            get_func_task_path(async_me), ("qux",), {})
Exemple #4
0
    def test_async_sqs_call(self):
        """
        Call a task with sqs async service.
        """

        async_sqs_me = import_and_get_task("tests.test_app.async_sqs_me")
        sqs_client_mock = mock.Mock()
        sqs_client_mock.get_queue_url = mock.MagicMock(
            return_value={
                'QueueUrl': 'https://us-east-1.queue.amazonaws.com/1'
            })
        sqs_client_mock.send_message = mock.MagicMock(
            return_value={
                'MD5OfMessageBody': 'string',
                'MD5OfMessageAttributes': 'string',
                'MessageId': '1234',
                'SequenceNumber': '1'
            })
        with mock.patch('zappa.async.SQS_CLIENT', sqs_client_mock,
                        create=True):
            # First check that it still runs synchronously by default
            self.assertEqual(async_sqs_me("123"),
                             "run async with sqs service when on lambda 123")

            # Now patch the environment to make it look like we are running on
            # AWS Lambda
            options = {
                'AWS_LAMBDA_FUNCTION_NAME': 'MyLambda',
                'AWS_REGION': 'us-east-1'
            }
            with mock.patch.dict(os.environ, options):
                async_sqs_me("qux")

        # And check the sqs client got invoked correctly
        sqs_client_mock.get_queue_url.assert_called_once_with(
            QueueName='MyLambda-zappa-async')
        sqs_client_mock.send_message.assert_called_once_with(
            QueueUrl='https://us-east-1.queue.amazonaws.com/1',
            MessageBody=json.dumps({
                "task_path":
                get_func_task_path(async_sqs_me),
                "capture_response":
                False,
                "response_id":
                None,
                "args": ["qux"],
                "kwargs": {},
                "zappaAsyncCommand":
                "zappa.async.route_sqs_task"
            }),
            DelaySeconds=0)
Exemple #5
0
def send_to_other_lambda(function_in_lambda, *args, **kwargs):
    """
    Call the function_in_lambda in another lambda instead of the running one
    and return the result.
    :param function_in_lambda: The function to call.
    :param args: The arguments to this function.
    :param kwargs: The lwargs to this function.
    :return: The result of this call.
    """
    lambda_function_name = os.environ.get('AWS_LAMBDA_FUNCTION_NAME')
    aws_region = os.environ.get('AWS_REGION')

    task_path = get_func_task_path(function_in_lambda)
    result = LambdaSyncResponse(lambda_function_name=lambda_function_name,
                                aws_region=aws_region).send(
                                    task_path, args, kwargs).response

    return result
Exemple #6
0
def run_lambda(data, map_function, compression, invoke_lambda):
    """
    Run a given map_function on the given data and return the result.

    For this:
    * the data is encoded (using compression or not),
    * a lambda function is invoked, which decoded the data, calls the map_function and encoded the result again
    * the result is decoded again and returned.
    :param data: The data that is sent to the lambda function
    :param map_function: The function that is called in the lambda on the data.
    :param compression: Turn on compression during streaming or not.
    :param invoke_lambda: Call another lambda or do everything in this lambda
    :return: The result of the function call.
    """
    encoded_data = encode_payload(data, compression)
    map_function = get_func_task_path(map_function)
    if not invoke_lambda:
        encoded_result = function_in_lambda(encoded_data, map_function,
                                            compression)
    else:
        encoded_result = send_to_other_lambda(function_in_lambda, encoded_data,
                                              map_function, compression)
    return decode_payload(encoded_result, compression)
Exemple #7
0
 def test_nofails_funcs(self):
     funk = import_and_get_task("tests.test_app.schedule_me")
     get_func_task_path(funk)
     is_from_router()
Exemple #8
0
 def test_nofails_funcs(self):
     funk = import_and_get_task("tests.test_app.async_me")
     get_func_task_path(funk)
     self.assertEqual(funk.__name__, 'async_me')
 def test_nofails_funcs(self):
     funk = import_and_get_task("tests.test_app.async_me")
     get_func_task_path(funk)
     self.assertEqual(funk.__name__, 'async_me')