I am trying to run spring boot application as serverless in AWS lambda and I am getting below exception while calling lambda function. Spring boot application successfully ran but it seems that it is going to fail to map the request
2018-09-25 06:11:50.717 INFO 1 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-09-25 06:11:50.823 INFO 1 --- [ main] **my.service.Application : Started Application in 7.405 seconds (JVM running for 8.939)**
START RequestId: decfc13c-c089-11e8-bacd-a37f1ba65629 Version: $LATEST
2018-09-25 06:11:50.994 ERROR 1 --- [ main] **c.a.s.p.i.s.AwsProxyHttpServletRequest : Called set character encoding to UTF-8 on a request without a content type. Character encoding will not be set
2018-09-25 06:11:51.175 ERROR 1 --- [ main] o.s.boot.web.support.ErrorPageFilter : Forwarding to error page from request [/] due to exception [null]**
java.lang.NullPointerException: null
at com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequest.getRemoteAddr(AwsProxyHttpServletRequest.java:575) ~[task/:na]
at org.springframework.web.servlet.FrameworkServlet.publishRequestHandledEvent(FrameworkServlet.java:1075) ~[task/:na]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[task/:na]
.........
2018-09-25 06:11:51.535 ERROR 1 --- [ main] s.p.i.s.AwsLambdaServletContainerHandler : Could not forward request
This is my StreamLambdaHandler java file.
public class StreamLambdaHandler implements RequestStreamHandler {
private static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
static {
try {
handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(Application.class);
} catch (ContainerInitializationException e) {
throw new RuntimeException("Could not initialize Spring Boot application", e);
}
}
#Override
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
throws IOException {
handler.proxyStream(inputStream, outputStream, context);
outputStream.close();
}
}
Looks like you might be hitting https://github.com/awslabs/aws-serverless-java-container/issues/172. According to the ticket, the fix will be available as part of the upcoming 1.2 release.
Related
I am writing simple helloworld application in spring batch, and I'm trying to validate the JobParameters with custom implementation of JobParametersValidator.
public class ParameterValidator implements JobParametersValidator{
#Override
public void validate(JobParameters parameters) throws JobParametersInvalidException {
//String parameter = parameters.getParameters().get("outputText");
System.out.println("jobparameters are ............ " + parameters);
//System.out.println("parameter is " + parameter);
//if(!StringUtils.hasText(parameter)) {
throw new JobParametersInvalidException("Parameter is missing.........");
//}
}
}
But when I tried to Sysout the JobParameters inside the validate method, parameters return null.
Here is my console out.
2021-11-26 10:06:32.457 INFO 11912 --- [ restartedMain] com.pack.SpringBatchDemo2Application : Starting SpringBatchDemo2Application using Java 16.0.2 on DESKTOP-T1L7IA7 with PID 11912 (D:\Workspace\EclipseWorkspaceSpringPractise\SpringBatchDemo2\target\classes started by arepa in D:\Workspace\EclipseWorkspaceSpringPractise\SpringBatchDemo2)
2021-11-26 10:06:32.458 INFO 11912 --- [ restartedMain] com.pack.SpringBatchDemo2Application : No active profile set, falling back to default profiles: default
2021-11-26 10:06:32.536 INFO 11912 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2021-11-26 10:06:33.575 INFO 11912 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2021-11-26 10:06:33.784 INFO 11912 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2021-11-26 10:06:33.920 INFO 11912 --- [ restartedMain] o.s.b.c.r.s.JobRepositoryFactoryBean : No database type set, using meta data indicating: POSTGRES
2021-11-26 10:06:34.262 INFO 11912 --- [ restartedMain] o.s.b.c.l.support.SimpleJobLauncher : No TaskExecutor has been set, defaulting to synchronous executor.
2021-11-26 10:06:34.484 INFO 11912 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2021-11-26 10:06:34.539 INFO 11912 --- [ restartedMain] com.pack.SpringBatchDemo2Application : Started SpringBatchDemo2Application in 2.596 seconds (JVM running for 4.056)
2021-11-26 10:06:34.544 INFO 11912 --- [ restartedMain] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: []
jobparameters are ............ {}
2021-11-26 10:06:34.713 INFO 11912 --- [ restartedMain] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-11-26 10:06:34.756 ERROR 11912 --- [ restartedMain] o.s.boot.SpringApplication : Application run failed
Here is my Job creation code.
#Component
public class HelloWorldJob {
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private StepBuilderFactory stepBuilderFactory;
public Step step() {
Tasklet tasklet = (contribution, chunkContext) -> {
return RepeatStatus.FINISHED;
};
return this.stepBuilderFactory.get("step1")
.tasklet(tasklet).build();
}
#Bean
public Job job() {
return this.jobBuilderFactory.get("job1").start(step()).validator(new ParameterValidator()).build();
}
}
Here is my code for triggering jobs.
#Component
public class TriggerJobLauncher {
#Autowired
private JobLauncher launcher;
#Autowired
private Job job;
public void triggerJob() throws JobExecutionAlreadyRunningException,
JobRestartException,
JobInstanceAlreadyCompleteException,
JobParametersInvalidException {
JobParameters parameters = new JobParametersBuilder().addParameter("aa", new JobParameter("Hello World")).toJobParameters();
launcher.run(job, parameters);
}
}
Spring boot application using gradle throwing follwoing error
2020-09-08 18:18:41.444 INFO 16780 --- [ main] o.s.boot.SpringApplication : Starting SpringApplication v2.4.0-SNAPSHOT using Java 14.0.2 on DESKTOP-5UQMCR2 with PID 16780 (C:\Users\jophi.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot\2.4.0-SNAPSHOT\28d1eed982ce2c51809e5542c993ab84faa55390\spring-boot-2.4.0-SNAPSHOT.jar started by jophi in D:\WorkSpace\DIY_Project\DIY\DIY)
2020-09-08 18:18:41.445 INFO 16780 --- [ main] o.s.boot.SpringApplication : No active profile set, falling back to default profiles: default
2020-09-08 18:18:41.524 ERROR 16780 --- [ main] o.s.boot.SpringApplication : Application run failed
java.lang.IllegalArgumentException: Sources must not be empty
at org.springframework.util.Assert.notEmpty(Assert.java:467) ~[spring-core-5.3.0-SNAPSHOT.jar:5.3.0-SNAPSHOT]
at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:404) ~[spring-boot-2.4.0-SNAPSHOT.jar:2.4.0-SNAPSHOT]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:325) ~[spring-boot-2.4.0-SNAPSHOT.jar:2.4.0-SNAPSHOT]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1280) ~[spring-boot-2.4.0-SNAPSHOT.jar:2.4.0-SNAPSHOT]
at org.springframework.boot.SpringApplication.main(SpringApplication.java:1296) ~[spring-boot-2.4.0-SNAPSHOT.jar:2.4.0-SNAPSHOT]
I think you should start you app by running the main class..
Your main class should look something:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
I want to create a cron job which is retry-able and only 1 instance should execute it when we deploy multiple instances of the application.
I have also referred #Recover annotated method is not discovered for a #Retryable method that also is #Scheduled, but I am unable to resolve the issue of ArrayIndexOutOfBoundsException.
I am using 2.1.8.RELEASE version spring-boot
#Configuration
#EnableScheduling
#EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
#EnableRetry
public class MyScheduler {
#Scheduled(cron = "0 16 16 * * *")
#SchedulerLock(name = "MyScheduler_lock", lockAtLeastForString = ""PT5M", lockAtMostForString ="PT14M")
#Retryable(value = Exception.class, maxAttempts = 2)
public void retryAndRecover() {
retry++;
log.info("Scheduling Service Failed " + retry);
throw new Exception();
}
#Recover
public void recover(Exception e, String str) {
log.info("Service recovering");
}
}
Detailed exception:
2019-12-07 19:42:00.109 INFO [my-service,false] 16767 --- [ scheduling-1] r.t.p.scheduler.MyScheduler : Scheduling Service Failed 1
2019-12-07 19:42:01.114 INFO [my-service,false] 16767 --- [ scheduling-1] r.t.p.scheduler.MyScheduler : Scheduling Service Failed 2
2019-12-07 19:42:01.123 ERROR [my-service,,,] 16767 --- [ scheduling-1] o.s.s.s.TaskUtils$LoggingErrorHandler : Unexpected error occurred in scheduled task.
java.lang.ArrayIndexOutOfBoundsException: arraycopy: last source index 1 out of bounds for object array[0]
at java.base/java.lang.System.arraycopy(Native Method) ~[na:na]
at org.springframework.retry.annotation.RecoverAnnotationRecoveryHandler$SimpleMetadata.getArgs(RecoverAnnotationRecoveryHandler.java:166) ~[spring-retry-1.2.1.RELEASE.jar:na]
at org.springframework.retry.annotation.RecoverAnnotationRecoveryHandler.recover(RecoverAnnotationRecoveryHandler.java:62) ~[spring-retry-1.2.1.RELEASE.jar:na]
Your recover method can't have more parameters than the main method (aside from the exception.
String str
In playing around with Spring Boot, ActiveMQ, and JmsTemplate, I noticed that it appears that message order is not always preserved. In reading on ActiveMQ, "Message Groups" are offered as a potential solution to preserving message order when sending to a topic. Is there a way to do this with JmsTemplate?
Add Note: I'm starting to think that JmsTemplate is nice for "getting launched", but has too many issues.
Sample code and console output posted below...
#RestController
public class EmptyControllerSB {
#Autowired
MsgSender msgSender;
#RequestMapping(method = RequestMethod.GET, value = { "/v1/msgqueue" })
public String getAccount() {
msgSender.sendJmsMessageA();
msgSender.sendJmsMessageB();
return "Do nothing...successfully!";
}
}
#Component
public class MsgSender {
#Autowired
JmsTemplate jmsTemplate;
void sendJmsMessageA() {
jmsTemplate.convertAndSend(new ActiveMQTopic("VirtualTopic.TEST-TOPIC"), "message A");
}
void sendJmsMessageB() {
jmsTemplate.convertAndSend(new ActiveMQTopic("VirtualTopic.TEST-TOPIC"), "message B");
}
}
#Component
public class MsgReceiver {
private final String consumerOne = "Consumer.myConsumer1.VirtualTopic.TEST-TOPIC";
private final String consumerTwo = "Consumer.myConsumer2.VirtualTopic.TEST-TOPIC";
#JmsListener(destination = consumerOne )
public void receiveMessage1(String strMessage) {
System.out.println("Received on #1a -> " + strMessage);
}
#JmsListener(destination = consumerOne )
public void receiveMessage2(String strMessage) {
System.out.println("Received on #1b -> " + strMessage);
}
#JmsListener(destination = consumerTwo )
public void receiveMessage3(String strMessage) {
System.out.println("Received on #2 -> " + strMessage);
}
}
Here's the console output (note the order of output in first sequence)...
\Intel\Intel(R) Management Engine Components\DAL;C:\WINDOWS\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files (x86)\gnupg\bin;C:\Users\LesR\AppData\Local\Microsoft\WindowsApps;c:\Gradle\gradle-5.0\bin;;C:\Program Files\JetBrains\IntelliJ IDEA 2018.3\bin;;.]
2019-04-03 09:23:08.408 INFO 13936 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-04-03 09:23:08.408 INFO 13936 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 672 ms
2019-04-03 09:23:08.705 INFO 13936 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-04-03 09:23:08.845 INFO 13936 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-04-03 09:23:08.877 INFO 13936 --- [ main] mil.navy.msgqueue.MsgqueueApplication : Started MsgqueueApplication in 1.391 seconds (JVM running for 1.857)
2019-04-03 09:23:14.949 INFO 13936 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-04-03 09:23:14.949 INFO 13936 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2019-04-03 09:23:14.952 INFO 13936 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 3 ms
Received on #2 -> message A
Received on #1a -> message B
Received on #1b -> message A
Received on #2 -> message B
<HIT DO-NOTHING ENDPOINT AGAIN>
Received on #1b -> message A
Received on #2 -> message A
Received on #1a -> message B
Received on #2 -> message B
BLUF - Add "?consumer.exclusive=true" to the declaration of the destination for the JmsListener annotation.
It seems that the solution is not that complex, especially if one abandons ActiveMQ's "message groups" in favor or "exclusive consumers". The drawback to the "message groups" is that the sender has to have prior knowledge of the potential partitioning of message consumers. If the producer has this knowledge, then "message groups" are a nice solution, as the solution is somewhat independent of the consumer.
But, a similar solution can be implemented from the consumer side, by having the consumer declare "exclusive consumer" on the queue. While I did not see anything in the JmsTemplate implementation that directly supports this, it seems that Spring's JmsTemplate implementation passes the queue name to ActiveMQ, and then ActiveMQ "does the right thing" and enforces the exclusive consumer behavior.
So...
Change the following...
private final String consumerOne = "Consumer.myConsumer1.VirtualTopic.TEST-TOPIC";
to...
private final String consumerOne = "Consumer.myConsumer1.VirtualTopic.TEST-TOPIC";?consumer.exclusive=true
Once I did this, only one of the two declared receive methods were invoked, and message order was maintained in all my test runs.
The CamelContextStartedEvent is called twice for the same camel context (camel-1). The issue might be the way I register the EventNotifier. You can reproduce the issue with Spring Initializr with Spring Boot 1.5.14, Spring Boot Camel Starter 2.21.1 and Spring Boot Web Starter.
See the logs:
2018-07-06 11:04:41.104 INFO 19092 --- [ main] o.a.camel.spring.SpringCamelContext : Apache Camel 2.21.1 (CamelContext: camel-1) is starting
2018-07-06 11:04:41.106 INFO 19092 --- [ main] o.a.c.m.ManagedManagementStrategy : JMX is enabled
2018-07-06 11:04:41.191 INFO 19092 --- [ main] o.a.camel.spring.SpringCamelContext : StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html
2018-07-06 11:04:41.193 INFO 19092 --- [ main] o.a.camel.spring.boot.RoutesCollector : Starting CamelMainRunController to ensure the main thread keeps running
2018-07-06 11:04:41.193 INFO 19092 --- [ main] o.a.camel.spring.SpringCamelContext : Total 0 routes, of which 0 are started
2018-07-06 11:04:41.194 INFO 19092 --- [ main] o.a.camel.spring.SpringCamelContext : Apache Camel 2.21.1 (CamelContext: camel-1) started in 0.090 seconds
2018-07-06 11:04:41.195 INFO 19092 --- [ main] c.e.bug.service.StartupEventNotifier : CamelContextStartedEvent for SpringCamelContext(camel-1) with spring id application:11223
2018-07-06 11:04:41.195 INFO 19092 --- [ main] c.e.bug.service.StartupEventNotifier : CamelContextStartedEvent for SpringCamelContext(camel-1) with spring id application:11223
2018-07-06 11:04:41.216 INFO 19092 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 11223 (http)
2018-07-06 11:04:41.221 INFO 19092 --- [ main] com.example.bug.BugApplication : Started BugApplication in 4.684 seconds (JVM running for 6.773)
The service that initializes the EventNotifier:
#Service
public class SchedulerService {
private final CamelContext camelContext;
private final StartupEventNotifier startupEventNotifier;
public SchedulerService(CamelContext camelContext, StartupEventNotifier startupEventNotifier) {
this.camelContext = camelContext;
this.startupEventNotifier = startupEventNotifier;
}
#PostConstruct
public void init() {
camelContext.getManagementStrategy().addEventNotifier(startupEventNotifier);
}
}
The EventNotifier:
#Component
public class StartupEventNotifier extends EventNotifierSupport {
private static final Logger logger = LoggerFactory.getLogger(StartupEventNotifier.class);
#Override
public void notify(EventObject event) throws Exception {
if (event instanceof CamelContextStartedEvent) {
logger.info("CamelContextStartedEvent for {}", event.getSource());
}
}
#Override
public boolean isEnabled(EventObject event) {
if (event instanceof CamelContextStartedEvent) {
return true;
}
return false;
}
}
application.yml:
camel:
springboot:
main-run-controller: true
server:
port: 11223
It is called twice, because it is registered twice. Once by you and once by Apache Camel. EventNotifier is registered automatically, if is found in Registry. Since your StartupEventNotifier is annotated as Component, it is part of Registry and Apache Camel registered it during CamelContext startup (You can see it in CamelAutoConfiguration line 424).
You have four options:
Remove your custom registration from SchedulerService.
Remove #Component annotation from StartupEventNotifier and register it with with camelContext.getManagementStrategy().addEventNotifier(new StartupEventNotifier())
Add duplicity check to your SchedulerService. Something like:
if (!context.getManagementStrategy().getEventNotifiers().contains(startupEventNotifier)){
context.getManagementStrategy().addEventNotifier(startupEventNotifier);
}
Register EventNotifier in #PostConstruct of RouteBuilder. It will be registered before automatic discovery is started and then it will be skipped in CamelAutoConfiguration (See line 422)