Несколько функций Spring Cloud в одном проекте для развертывания на AWS Lambda - PullRequest
0 голосов
/ 23 ноября 2018

Мне может понадобиться помощь здесь ...

Я использую Spring Cloud Function и хочу развернуть свои функции на AWS Lambda, используя адаптер для AWS.

MyКласс приложения выглядит следующим образом:

package example;

@SpringBootApplication
public class SpringCloudFunctionApiGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudFunctionApiGatewayApplication.class, args);
    }

}

Функция 1 выглядит следующим образом:

package example;

@Component
public class StoreFunction implements Consumer<Message<DemoEntity>>{

    @Override
    public void accept(Message<DemoEntity> t) {

        System.out.println("Stored entity " + ((DemoEntity)t.getPayload()).getName());
        return;
    }
}

Наконец, мой обработчик функций выглядит следующим образом:

package example;

public class TestFunctionHandler extends SpringBootApiGatewayRequestHandler {

}

Эта настройкаработает отлично.При развертывании в Lambda я предоставляю example.TestFunctionHandler в качестве обработчика в консоли AWS, и Spring Cloud автоматически распознает, что example.QueryFunction является единственной функцией в контексте.

Вывод журнала выглядит следующим образом:

START RequestId: 3bd996e7-ef5e-11e8-9829-1f50e2b93b6c Version: $LATEST
20:27:45.821 [main] INFO org.springframework.cloud.function.adapter.aws.SpringFunctionInitializer - Initializing: class de.margul.awstutorials.springcloudfunction.apigateway.SpringCloudFunctionApiGatewayApplication

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                        

2018-11-23 20:27:48.221  INFO 1 --- [           main] lambdainternal.LambdaRTEntry             : Starting LambdaRTEntry on ip-10-153-127-174.ec2.internal with PID 1 (/var/runtime/lib/LambdaJavaRTEntry-1.0.jar started by sbx_user1060 in /)
2018-11-23 20:27:48.242  INFO 1 --- [           main] lambdainternal.LambdaRTEntry             : No active profile set, falling back to default profiles: default
2018-11-23 20:27:52.081  INFO 1 --- [           main] lambdainternal.LambdaRTEntry             : Started LambdaRTEntry in 5.941 seconds (JVM running for 7.429)
Stored entity John Doe
END RequestId: 3bd996e7-ef5e-11e8-9829-1f50e2b93b6c
REPORT RequestId: 3bd996e7-ef5e-11e8-9829-1f50e2b93b6c  Duration: 7113.98 ms    Billed Duration: 7200 ms    Memory Size: 1088 MB    Max Memory Used: 113 MB 

Теперь моя проблема возникает здесь.Я хочу иметь несколько функций в одном проекте.Я знаю, что в Lambda может быть только одна функция на развертывание.Однако по причинам обслуживания кода (в реальном проекте есть некоторый общий код, а также конфигурации), мы хотим, чтобы все функции были в одном проекте, многократно развертывали проект и определяли в развертывании, что является соответствующей функцией.

Использование родного AWS SDK для Lambda, это было легко (например, в этом примере в разделе 4.2): одна реализация RequestStreamHandler , с несколькими методами (даже если RequestStreamHandler имеет только один handleRequest () метод).Дело в том, что можно определить соответствующую функцию как обработчик: package.ClassName :: methodName

Однако это не работает с Spring Cloud Function (так как у нас может быть только один обработчик,в данном случае это TestFunctionHandler ). В документации упоминается , что возможны несколько функций, указав function.name в application.properties или в качестве переменной среды Lambda FUNCTION_NAME .В любом случае, у меня это не работает.

Моя функция 2 выглядит следующим образом:

package example;

@Component
public class QueryFunction implements Function<Message<String>, Message<DemoEntity>>{

    @Override
    public Message<DemoEntity> apply(Message<String> m) {

        String name = m.getPayload();

        DemoEntity response = new DemoEntity();
        response.setName(name);
        Message<DemoEntity> message = MessageBuilder
                .withPayload(response)
                .setHeader("contentType", "application/json")
                .build();
        return message;
    }
}

В моем application.properties у меня есть эта строка:

function.name = example.StoreFunction

То же самое применимо, если я создаю переменную среды FUNCTION_NAME: example.StoreFunction

Если я сейчас разверну библиотеку и запусту ее, я получу следующие журналы:

START RequestId: 67e64098-ef5d-11e8-bdbf-9ddadadef0ce Version: $LATEST
20:21:50.802 [main] INFO org.springframework.cloud.function.adapter.aws.SpringFunctionInitializer - Initializing: class example.SpringCloudFunctionApiGatewayApplication

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                        

2018-11-23 20:21:53.684  INFO 1 --- [           main] lambdainternal.LambdaRTEntry             : Starting LambdaRTEntry on ip-10-153-127-174.ec2.internal with PID 1 (/var/runtime/lib/LambdaJavaRTEntry-1.0.jar started by sbx_user1059 in /)
2018-11-23 20:21:53.687  INFO 1 --- [           main] lambdainternal.LambdaRTEntry             : No active profile set, falling back to default profiles: default
2018-11-23 20:21:57.488  INFO 1 --- [           main] lambdainternal.LambdaRTEntry             : Started LambdaRTEntry in 6.353 seconds (JVM running for 8.326)
No function defined: java.lang.IllegalStateException
java.lang.IllegalStateException: No function defined
    at org.springframework.cloud.function.adapter.aws.SpringFunctionInitializer.apply(SpringFunctionInitializer.java:134)
    at org.springframework.cloud.function.adapter.aws.SpringBootRequestHandler.handleRequest(SpringBootRequestHandler.java:48)

END RequestId: 67e64098-ef5d-11e8-bdbf-9ddadadef0ce
REPORT RequestId: 67e64098-ef5d-11e8-bdbf-9ddadadef0ce  Duration: 7454.73 ms    Billed Duration: 7500 ms    Memory Size: 1088 MB    Max Memory Used: 130 MB 

Мы высоко ценим любую помощь!

1 Ответ

0 голосов
/ 24 ноября 2018

Хорошо, проблема, очевидно, заключалась в моих ограниченных знаниях о Spring Beans.

После просмотра списка всех доступных bean-компонентов в контексте стало ясно, что мне нужно использовать имя класса, но начиная снижний регистр, то есть function.name = storeFunction или function.name = queryFunction .

Изменить, чтобы подробно объяснить мое решение:

ВВ моем проекте у меня есть несколько функций, подобных этой:

@Component
public class StoreFunction implements Consumer<String>{

    @Override
    public void accept(String s) {

        // Logic comes here
    }
}

@Component
public class QueryFunction implements Function<String, String>{

    @Override
    public void apply(String s) {

        return s;
    }
}

Затем я регистрирую их как bean-компоненты, например, вот так:

@SpringBootApplication
public class SpringCloudFunctionApiGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudFunctionApiGatewayApplication.class, args);
    }

    @Bean
    StoreFunction storeFunction(){
        return new StoreFunction();
    }

    @Bean
    QueryFunction queryFunction(){
        return new QueryFunction();
    }
}

Теперь у меня есть две компоненты storeFunction и queryFunction (имена методов @Bean выше) доступны в моем контексте Spring.

Наконец, я должен сказать Spring, какую из функций вызывать.Это можно сделать, создав переменную среды FUNCTION_NAME и присвоив ей одно из имен bean-компонентов.

Когда я сейчас разверну проект в AWS Lambda, я должен сообщить Lambda, какая функция вызывается (поскольку Lambda может тольковызывать одну функцию для каждого развертывания).

Кстати, я создал учебник для этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...