AWS ECS: Task Being Mapped to Wrong Target Group - java
I have a Spring project with 2 modules: Pets and Owners, each a microservice that gets its data from a single MySQL DB. When I push the two into a single Docker container with 2 tasks -- 1 for each microservice -- they both get up and running, and the tasks are mapped to different host ports (32768 & 32769). However, when I go to http://{elb-dns}/pet, I get a 404, but when I go to http://{elb-dns}/owner, it returns the expected data. I've learned the pet task gets mapped to the wrong Target Group, but idk why.
After creating the ECS cluster, this is what the following AWS CLI "describe" commands output:
aws ecs describe-clusters --cluster vets --region us-west-2
{
"clusters": [
{
"status": "ACTIVE",
"clusterName": "vets",
"registeredContainerInstancesCount": 3,
"pendingTasksCount": 0,
"runningTasksCount": 4,
"activeServicesCount": 2,
"clusterArn": "arn:aws:ecs:us-west-2:224265390743:cluster/vets"
}
],
"failures": []
}
aws elbv2 describe-target-groups --name vets0-tg --region us-west-2
{
"TargetGroups": [
{
"HealthCheckPath": "/",
"HealthCheckIntervalSeconds": 60,
"VpcId": "vpc-0540fe4c35343c7c9",
"Protocol": "HTTP",
"HealthCheckTimeoutSeconds": 30,
"HealthCheckProtocol": "HTTP",
"LoadBalancerArns": [
"arn:aws:elasticloadbalancing:us-west-2:224265390743:loadbalancer/app/vets-elb/5643eac9e4d51da0"
],
"UnhealthyThresholdCount": 3,
"HealthyThresholdCount": 5,
"TargetGroupArn": "arn:aws:elasticloadbalancing:us-west-2:224265390743:targetgroup/vets0-tg/8fec38deef74b8f1",
"Matcher": {
"HttpCode": "200"
},
"HealthCheckPort": "traffic-port",
"Port": 8080,
"TargetGroupName": "vets0-tg"
}
]
}
aws elbv2 describe-target-groups --name vets1-tg --region us-west-2
{
"TargetGroups": [
{
"HealthCheckPath": "/",
"HealthCheckIntervalSeconds": 60,
"VpcId": "vpc-0540fe4c35343c7c9",
"Protocol": "HTTP",
"HealthCheckTimeoutSeconds": 30,
"HealthCheckProtocol": "HTTP",
"LoadBalancerArns": [
"arn:aws:elasticloadbalancing:us-west-2:224265390743:loadbalancer/app/vets-elb/5643eac9e4d51da0"
],
"UnhealthyThresholdCount": 3,
"HealthyThresholdCount": 5,
"TargetGroupArn": "arn:aws:elasticloadbalancing:us-west-2:224265390743:targetgroup/vets1-tg/b4ca3cafcaebdc78",
"Matcher": {
"HttpCode": "200"
},
"HealthCheckPort": "traffic-port",
"Port": 8080,
"TargetGroupName": "vets1-tg"
}
]
}
aws ecs describe-task-definition --task-definition vets-rest-pet:25 --region us-west-2
{
"taskDefinition": {
"status": "ACTIVE",
"networkMode": "bridge",
"family": "vets-rest-pet",
"requiresAttributes": [
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
},
{
"name": "com.amazonaws.ecs.capability.ecr-auth"
},
{
"name": "com.amazonaws.ecs.capability.task-iam-role"
},
{
"name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
}
],
"volumes": [],
"taskRoleArn": "arn:aws:iam::224265390743:role/MicroECSTaskRole",
"taskDefinitionArn": "arn:aws:ecs:us-west-2:224265390743:task-definition/vets-rest-pet:25",
"containerDefinitions": [
{
"environment": [
{
"name": "SPRING_DATASOURCE_USERNAME",
"value": "***"
},
{
"name": "SERVICE_ENDPOINT",
"value": "***.us-west-2.elb.amazonaws.com"
},
{
"name": "SPRING_DATASOURCE_URL",
"value": "***"
},
{
"name": "SPRING_DATASOURCE_PASSWORD",
"value": "***"
},
{
"name": "SPRING_PROFILES_ACTIVE",
"value": "mysql"
}
],
"name": "vets-rest-pet",
"mountPoints": [],
"image": "224265390743.dkr.ecr.us-west-2.amazonaws.com/vets-rest-pet:latest",
"dockerLabels": {
"string": "string"
},
"cpu": 1024,
"portMappings": [
{
"protocol": "tcp",
"containerPort": 8080,
"hostPort": 0
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-region": "us-west-2",
"awslogs-stream-prefix": "vets",
"awslogs-group": "ECSLogGroup-vets"
}
},
"memory": 1024,
"essential": true,
"volumesFrom": []
}
],
"revision": 25
}
}
aws ecs describe-task-definition --task-definition vets-rest-owner:18 --region us-west-2
{
"taskDefinition": {
"status": "ACTIVE",
"networkMode": "bridge",
"family": "vets-rest-owner",
"requiresAttributes": [
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
},
{
"name": "com.amazonaws.ecs.capability.ecr-auth"
},
{
"name": "com.amazonaws.ecs.capability.task-iam-role"
},
{
"name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
},
{
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
}
],
"volumes": [],
"taskRoleArn": "arn:aws:iam::224265390743:role/MicroECSTaskRole",
"taskDefinitionArn": "arn:aws:ecs:us-west-2:224265390743:task-definition/vets-rest-owner:18",
"containerDefinitions": [
{
"environment": [
{
"name": "SPRING_DATASOURCE_USERNAME",
"value": "***"
},
{
"name": "SERVICE_ENDPOINT",
"value": "***.us-west-2.elb.amazonaws.com"
},
{
"name": "SPRING_DATASOURCE_URL",
"value": "***"
},
{
"name": "SPRING_DATASOURCE_PASSWORD",
"value": "***"
},
{
"name": "SPRING_PROFILES_ACTIVE",
"value": "mysql"
}
],
"name": "vets-rest-owner",
"mountPoints": [],
"image": "224265390743.dkr.ecr.us-west-2.amazonaws.com/vets-rest-owner:latest",
"dockerLabels": {
"string": "string"
},
"cpu": 1024,
"portMappings": [
{
"protocol": "tcp",
"containerPort": 8080,
"hostPort": 0
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-region": "us-west-2",
"awslogs-stream-prefix": "vets",
"awslogs-group": "ECSLogGroup-vets"
}
},
"memory": 1024,
"essential": true,
"volumesFrom": []
}
],
"revision": 18
}
}
aws elbv2 describe-load-balancers --region us-west-2
{
"LoadBalancers": [
{
"VpcId": "vpc-0540fe4c35343c7c9",
"LoadBalancerArn": "arn:aws:elasticloadbalancing:us-west-2:224265390743:loadbalancer/app/vets-elb/5643eac9e4d51da0",
"State": {
"Code": "active"
},
"DNSName": "***.us-west-2.elb.amazonaws.com",
"SecurityGroups": [
"sg-09beda52a500a27fb"
],
"LoadBalancerName": "vets-elb",
"CreatedTime": "2018-03-27T02:55:14.510Z",
"Scheme": "internet-facing",
"Type": "application",
"CanonicalHostedZoneId": "Z1H1FL5HABSF5",
"AvailabilityZones": [
{
"SubnetId": "subnet-04bf10c7538cae458",
"ZoneName": "us-west-2c"
},
{
"SubnetId": "subnet-070b0cf7074abe6a4",
"ZoneName": "us-west-2b"
},
{
"SubnetId": "subnet-0a88aaf68def9cd1e",
"ZoneName": "us-west-2a"
}
]
}
]
}
aws elbv2 describe-listeners --load-balancer-arn arn:aws:elasticloadbalancing:us-west-2:224265390743:loadbalancer/app/vets-elb/5643eac9e4d51da0 --region us-west-2
{
"Listeners": [
{
"Protocol": "HTTP",
"DefaultActions": [
{
"TargetGroupArn": "arn:aws:elasticloadbalancing:us-west-2:224265390743:targetgroup/vets-elb-tg/fff73d84613d20d9",
"Type": "forward"
}
],
"LoadBalancerArn": "arn:aws:elasticloadbalancing:us-west-2:224265390743:loadbalancer/app/vets-elb/5643eac9e4d51da0",
"Port": 80,
"ListenerArn": "arn:aws:elasticloadbalancing:us-west-2:224265390743:listener/app/vets-elb/5643eac9e4d51da0/0ff4e63088aede1c"
}
]
}
aws elbv2 describe-rules --listener-arn arn:aws:elasticloadbalancing:us-west-2:224265390743:listener/app/vets-elb/5643eac9e4d51da0/0ff4e63088aede1c --region us-west-2
{
"Rules": [
{
"Priority": "363",
"Conditions": [
{
"Field": "path-pattern",
"Values": [
"/*"
]
}
],
"RuleArn": "arn:aws:elasticloadbalancing:us-west-2:224265390743:listener-rule/app/vets-elb/5643eac9e4d51da0/0ff4e63088aede1c/d8fdc1195564af14",
"IsDefault": false,
"Actions": [
{
"TargetGroupArn": "arn:aws:elasticloadbalancing:us-west-2:224265390743:targetgroup/vets0-tg/8fec38deef74b8f1",
"Type": "forward"
}
]
},
{
"Priority": "458",
"Conditions": [
{
"Field": "path-pattern",
"Values": [
"/*"
]
}
],
"RuleArn": "arn:aws:elasticloadbalancing:us-west-2:224265390743:listener-rule/app/vets-elb/5643eac9e4d51da0/0ff4e63088aede1c/40d6a6e2dd71eaa5",
"IsDefault": false,
"Actions": [
{
"TargetGroupArn": "arn:aws:elasticloadbalancing:us-west-2:224265390743:targetgroup/vets1-tg/b4ca3cafcaebdc78",
"Type": "forward"
}
]
},
{
"Priority": "default",
"Conditions": [],
"RuleArn": "arn:aws:elasticloadbalancing:us-west-2:224265390743:listener-rule/app/vets-elb/5643eac9e4d51da0/0ff4e63088aede1c/24df0f9b37383df2",
"IsDefault": true,
"Actions": [
{
"TargetGroupArn": "arn:aws:elasticloadbalancing:us-west-2:224265390743:targetgroup/vets-elb-tg/fff73d84613d20d9",
"Type": "forward"
}
]
}
]
}
I've confirmed that when deployed separately each microservice works in isolation. I'm using an Application Load Balancer, and each microservice has its own target group. I'm not sure what else to try or check. Has anyone experienced a similar problem? Where else should I look for clues?
Update 1
I changed the logging level to TRACE and learned that all /pet and /owner calls are being routed to the owner task exclusively. The following logs are from the owner task when I try http://{elb-dns}/pet/1:
9:00.590 DEBUG 7 - [nio-8080-exec-8] o.s.b.w.f.OrderedRequestContextFilter : Bound request context to thread: org.apache.catalina.connector.RequestFacade#446e699a
9:00.590 TRACE 7 - [nio-8080-exec-8] o.s.b.a.trace.WebRequestTraceFilter : Processing request GET /pet/1
9:00.590 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Bound request context to thread: org.apache.catalina.connector.RequestFacade#446e699a
9:00.590 DEBUG 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/pet/1]
9:00.590 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#29ef6856] in DispatcherServlet with name 'dispatcherServlet'
9:00.590 TRACE 7 - [nio-8080-exec-8] o.s.w.s.handler.SimpleUrlHandlerMapping : No handler mapping found for [/pet/1]
9:00.590 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping#2f162cc0] in DispatcherServlet with name 'dispatcherServlet'
9:00.590 DEBUG 7 - [nio-8080-exec-8] o.s.b.a.e.mvc.EndpointHandlerMapping : Looking up handler method for path /pet/1
9:00.591 DEBUG 7 - [nio-8080-exec-8] o.s.b.a.e.mvc.EndpointHandlerMapping : Did not find handler method for [/pet/1]
9:00.591 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#b40bb6e] in DispatcherServlet with name 'dispatcherServlet'
9:00.591 DEBUG 7 - [nio-8080-exec-8] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /pet/1
9:00.591 DEBUG 7 - [nio-8080-exec-8] s.w.s.m.m.a.RequestMappingHandlerMapping : Did not find handler method for [/pet/1]
9:00.591 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping#34a75079] in DispatcherServlet with name 'dispatcherServlet'
9:00.591 TRACE 7 - [nio-8080-exec-8] o.s.w.s.h.BeanNameUrlHandlerMapping : No handler mapping found for [/pet/1]
9:00.591 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping#841e575] in DispatcherServlet with name 'dispatcherServlet'
9:00.591 DEBUG 7 - [nio-8080-exec-8] o.s.d.r.w.BasePathAwareHandlerMapping : Looking up handler method for path /pet/1
9:00.591 DEBUG 7 - [nio-8080-exec-8] o.s.d.r.w.BasePathAwareHandlerMapping : Did not find handler method for [/pet/1]
9:00.591 DEBUG 7 - [nio-8080-exec-8] o.s.d.r.w.RepositoryRestHandlerMapping : Looking up handler method for path /pet/1
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.d.r.w.RepositoryRestHandlerMapping : Found 1 matching mapping(s) for [/pet/1] : [{[/{repository}/{id}],methods=[GET],produces=[application/hal+json]}]
9:00.592 DEBUG 7 - [nio-8080-exec-8] o.s.d.r.w.RepositoryRestHandlerMapping : Did not find handler method for [/pet/1]
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#346a361] in DispatcherServlet with name 'dispatcherServlet'
9:00.592 DEBUG 7 - [nio-8080-exec-8] o.s.w.s.handler.SimpleUrlHandlerMapping : Matching patterns for request [/pet/1] are [\/**]
9:00.592 DEBUG 7 - [nio-8080-exec-8] o.s.w.s.handler.SimpleUrlHandlerMapping : URI Template variables for request [/pet/1] are {}
9:00.592 DEBUG 7 - [nio-8080-exec-8] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapping [/pet/1] to HandlerExecutionChain with handler [ResourceHttpRequestHandler [locations=[ServletContext resource [/], class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver#5471388b]]] and 1 interceptor
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Testing handler adapter [org.springframework.data.rest.webmvc.RepositoryRestHandlerAdapter#94f6bfb]
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Testing handler adapter [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#2cac4385]
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Testing handler adapter [org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter#186978a6]
9:00.592 DEBUG 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Last-Modified value for [/pet/1] is: -1
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.w.s.r.ResourceHttpRequestHandler : Applying "invalid path" checks to path: pet/1
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.w.s.resource.PathResourceResolver : Resolving resource for request path "pet/1"
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.w.s.resource.PathResourceResolver : Checking location: ServletContext resource [/]
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.w.s.resource.PathResourceResolver : No match for location: ServletContext resource [/]
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.w.s.resource.PathResourceResolver : Checking location: class path resource [META-INF/resources/]
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.w.s.resource.PathResourceResolver : No match for location: class path resource [META-INF/resources/]
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.w.s.resource.PathResourceResolver : Checking location: class path resource [resources/]
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.w.s.resource.PathResourceResolver : No match for location: class path resource [resources/]
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.w.s.resource.PathResourceResolver : Checking location: class path resource [static/]
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.w.s.resource.PathResourceResolver : No match for location: class path resource [static/]
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.w.s.resource.PathResourceResolver : Checking location: class path resource [public/]
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.w.s.resource.PathResourceResolver : No match for location: class path resource [public/]
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.w.s.r.ResourceHttpRequestHandler : No matching resource found - returning 404
9:00.592 DEBUG 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
9:00.592 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade#446e699a
9:00.592 DEBUG 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Successfully completed request
9:00.592 TRACE 7 - [nio-8080-exec-8] ationConfigEmbeddedWebApplicationContext : Publishing event in org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#77a567e1: ServletRequestHandledEvent: url=[/pet/1]; pet=[10.0.1.219]; method=[GET]; servlet=[dispatcherServlet]; session=[null]; user=[null]; time=[2ms]; status=[OK]
9:00.592 DEBUG 7 - [nio-8080-exec-8] o.s.b.w.f.OrderedRequestContextFilter : Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade#446e699a
9:00.593 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Bound request context to thread: org.apache.catalina.core.ApplicationHttpRequest#6a03dc7
9:00.593 DEBUG 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/error]
9:00.593 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#29ef6856] in DispatcherServlet with name 'dispatcherServlet'
9:00.593 TRACE 7 - [nio-8080-exec-8] o.s.w.s.handler.SimpleUrlHandlerMapping : No handler mapping found for [/error]
9:00.593 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping#2f162cc0] in DispatcherServlet with name 'dispatcherServlet'
9:00.593 DEBUG 7 - [nio-8080-exec-8] o.s.b.a.e.mvc.EndpointHandlerMapping : Looking up handler method for path /error
9:00.593 DEBUG 7 - [nio-8080-exec-8] o.s.b.a.e.mvc.EndpointHandlerMapping : Did not find handler method for [/error]
9:00.593 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#b40bb6e] in DispatcherServlet with name 'dispatcherServlet'
9:00.593 DEBUG 7 - [nio-8080-exec-8] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /error
9:00.593 TRACE 7 - [nio-8080-exec-8] s.w.s.m.m.a.RequestMappingHandlerMapping : Found 2 matching mapping(s) for [/error] : [{[/error],produces=[text/html]}, {[/error]}]
9:00.594 DEBUG 7 - [nio-8080-exec-8] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)]
9:00.594 DEBUG 7 - [nio-8080-exec-8] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'basicErrorController'
9:00.594 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Testing handler adapter [org.springframework.data.rest.webmvc.RepositoryRestHandlerAdapter#94f6bfb]
9:00.594 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Testing handler adapter [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#2cac4385]
9:00.594 DEBUG 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Last-Modified value for [/error] is: -1
9:00.594 DEBUG 7 - [nio-8080-exec-8] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
9:00.594 TRACE 7 - [nio-8080-exec-8] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.orm.jpa.EntityManagerHolder#556e96bc] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#47c4ecdc] to thread [http-nio-8080-exec-8]
9:00.594 TRACE 7 - [nio-8080-exec-8] .w.s.m.m.a.ServletInvocableHandlerMethod : Invoking 'org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml' with arguments [org.apache.catalina.core.ApplicationHttpRequest#6a03dc7, org.apache.catalina.connector.ResponseFacade#1a8818e]
9:00.595 TRACE 7 - [nio-8080-exec-8] .w.s.m.m.a.ServletInvocableHandlerMethod : Method [org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml] returned [ModelAndView: reference to view with name 'error'; model is {timestamp=Sat Mar 24 9:00 GMT 2018, status=404, error=Not Found, message=No message available, path=/pet/1}]
9:00.595 DEBUG 7 - [nio-8080-exec-8] o.s.w.s.v.ContentNegotiatingViewResolver : Requested media types are [text/html, text/html;q=0.8] based on Accept header types and producible media types [text/html])
9:00.595 DEBUG 7 - [nio-8080-exec-8] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'error'
9:00.595 DEBUG 7 - [nio-8080-exec-8] o.s.w.s.v.ContentNegotiatingViewResolver : Returning [org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$SpelView#7a8fa663] based on requested media type 'text/html'
9:00.595 DEBUG 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Rendering view [org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$SpelView#7a8fa663] in DispatcherServlet with name 'dispatcherServlet'
9:00.595 TRACE 7 - [nio-8080-exec-8] o.s.util.PropertyPlaceholderHelper : Resolved placeholder 'timestamp'
9:00.595 TRACE 7 - [nio-8080-exec-8] o.s.util.PropertyPlaceholderHelper : Resolved placeholder 'error'
9:00.595 TRACE 7 - [nio-8080-exec-8] o.s.util.PropertyPlaceholderHelper : Resolved placeholder 'status'
9:00.595 TRACE 7 - [nio-8080-exec-8] o.s.util.PropertyPlaceholderHelper : Resolved placeholder 'message'
9:00.595 TRACE 7 - [nio-8080-exec-8] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.orm.jpa.EntityManagerHolder#556e96bc] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#47c4ecdc] from thread [http-nio-8080-exec-8]
9:00.595 DEBUG 7 - [nio-8080-exec-8] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor
9:00.595 DEBUG 7 - [nio-8080-exec-8] o.s.orm.jpa.EntityManagerFactoryUtils : Closing JPA EntityManager
9:00.595 TRACE 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Cleared thread-bound request context: org.apache.catalina.core.ApplicationHttpRequest#6a03dc7
9:00.595 DEBUG 7 - [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Successfully completed request
9:00.595 TRACE 7 - [nio-8080-exec-8] ationConfigEmbeddedWebApplicationContext : Publishing event in org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#77a567e1: ServletRequestHandledEvent: url=[/error]; pet=[10.0.1.219]; method=[GET]; servlet=[dispatcherServlet]; session=[null]; user=[null]; time=[2ms]; status=[OK]
That same call produces no logs in the pet task, indicating that it's not getting routed to the correct task in the container. So I'm still stuck on this problem.
Update 2
The ELB logs show that, for both /pet and /owner, all calls are being routed to the same Target Group. However, /pet should be routed to one TG, and /owner should be routed to the other. To be clear, I have 3 TG's: one on container port 8080 for /pet, one on container port 8080 for /owner, and one on container port 80 that accepts HTTP requests. All three TG's are in the same VPC.
http 03:48:22.439446Z app/vets-elb/ab3d7952d0ea2843 76.102.41.144:61442 10.0.12.74:32768 0.002 0.020 0.000 200 200 263 1259 "GET http://vets-elb-1925600148.us-west-2.elb.amazonaws.com:80/owner HTTP/1.1" "PostmanRuntime/6.4.1" - - arn:aws:elasticloadbalancing:us-west-2:224265390743:targetgroup/vets0-tg/16a5158616c45834 "Root=1-5ab71c06-4798a50a19129492453fd34c" "-" "-" 52
http 03:48:29.581797Z app/vets-elb/ab3d7952d0ea2843 76.102.41.144:61442 10.0.11.42:32768 0.000 0.006 0.000 404 404 263 319 "GET http://vets-elb-1925600148.us-west-2.elb.amazonaws.com:80/pet HTTP/1.1" "PostmanRuntime/6.4.1" - - arn:aws:elasticloadbalancing:us-west-2:224265390743:targetgroup/vets0-tg/16a5158616c45834 "Root=1-5ab71c0d-cff47d0a6bb893c0bc1b9b88" "-" "-" 52
The "rules" section of your ALB setup looks like the problem to me. They both have the pattern set to /* ... which means you don't tell it anywhere that /pets/* goes to one target and /owners/* to another.
After looking more closely at the AWS CLI output, I noticed that I have incorrectly stated the rules. They both state:
"Conditions": [
{
"Field": "path-pattern",
"Values": [
"/*"
]
}
]
But rather, they should state:
"Conditions": [
{
"Field": "path-pattern",
"Values": [
"/pet*"
]
}
]
and
"Conditions": [
{
"Field": "path-pattern",
"Values": [
"/owner*"
]
}
]
Related
Spring Webflux doOnCancel is not invoked when an app is deployed to Kubernetes
I have a controller with an endpoint that provide a flux like this reported below. When the app is deployed to kubernetes, methods doOnCancel and doOnTerminate are not invoked. Locally instead, it works like a charm (when the tab of the browser is closed as instance). #Slf4j #RestController public class TestController { ... #GetMapping(value = "/test", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> testStream() { log.info("Requested test streaming"); return mySink.asFlux() .startWith("INIT TEST") .doOnCancel(() -> log.info("On cancel")) .doOnTerminate(() -> log.info("On terminate")); } ... } 2022-08-06 18:25:42.115 INFO 3685 --- [ main] com.wuase.sinkdemo.SinkDemoApplication : Starting SinkDemoApplication using Java 1.8.0_252 on aniello-pc with PID 3685 (/home/pc/eclipse-workspace/sink-demo/target/classes started by pc in /home/pc/eclipse-workspace/sink-demo) 2022-08-06 18:25:42.124 INFO 3685 --- [ main] com.wuase.sinkdemo.SinkDemoApplication : No active profile set, falling back to 1 default profile: "default" 2022-08-06 18:25:44.985 INFO 3685 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port 8080 2022-08-06 18:25:45.018 INFO 3685 --- [ main] com.wuase.sinkdemo.SinkDemoApplication : Started SinkDemoApplication in 3.737 seconds (JVM running for 5.36) 2022-08-06 18:26:09.706 INFO 3685 --- [or-http-epoll-3] com.wuase.sinkdemo.TestController : Requested test streaming 2022-08-06 18:26:14.799 INFO 3685 --- [or-http-epoll-3] com.wuase.sinkdemo.TestController : On cancel Has anyone encountred the same problem? Any idea about that?
Spring Boot React in separate packages
I have a spring boot, java 8 API that I wanted to add a React front end to to make API operations easier to navigate and use. I used JHipster generator to generate a React app. Then I just took the web portion and dropped into my app, however whenever I run the Spring Boot application and try to navigate to port :8080 it, I get the following page: And the following error in the console: 2019-07-15 15:07:21.414 INFO 29145 --- [)-10.15.114.229] o.a.c.c.C.[.[.[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2019-07-15 15:07:21.414 INFO 29145 --- [)-10.15.114.229] o.s.w.s.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2019-07-15 15:07:21.414 DEBUG 29145 --- [)-10.15.114.229] o.s.w.s.DispatcherServlet : Detected StandardServletMultipartResolver 2019-07-15 15:07:21.426 DEBUG 29145 --- [)-10.15.114.229] o.s.w.s.DispatcherServlet : enableLoggingRequestDetails='false': request parameters and headers will be masked to prevent unsafe logging of potentially sensitive data 2019-07-15 15:07:21.426 INFO 29145 --- [)-10.15.114.229] o.s.w.s.DispatcherServlet : Completed initialization in 12 ms 2019-07-15 15:07:25.079 DEBUG 29145 --- [nio-8080-exec-1] o.s.w.s.DispatcherServlet : GET "/", parameters={} 2019-07-15 15:07:25.093 DEBUG 29145 --- [nio-8080-exec-1] s.d.s.w.PropertySourcedRequestMappingHandlerMapping : looking up handler for path: / 2019-07-15 15:07:25.128 DEBUG 29145 --- [nio-8080-exec-1] o.s.w.s.h.SimpleUrlHandlerMapping : Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"] 2019-07-15 15:07:25.130 DEBUG 29145 --- [nio-8080-exec-1] o.s.w.s.r.ResourceHttpRequestHandler : Resource not found 2019-07-15 15:07:25.131 DEBUG 29145 --- [nio-8080-exec-1] o.s.w.s.DispatcherServlet : Completed 404 NOT_FOUND 2019-07-15 15:07:25.152 DEBUG 29145 --- [nio-8080-exec-1] o.s.w.s.DispatcherServlet : "ERROR" dispatch for GET "/error", parameters={} 2019-07-15 15:07:25.153 DEBUG 29145 --- [nio-8080-exec-1] s.d.s.w.PropertySourcedRequestMappingHandlerMapping : looking up handler for path: /error 2019-07-15 15:07:25.167 DEBUG 29145 --- [nio-8080-exec-1] o.s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) 2019-07-15 15:07:25.199 DEBUG 29145 --- [nio-8080-exec-1] o.s.w.s.v.ContentNegotiatingViewResolver : Selected 'text/html' given [text/html, text/html;q=0.8] 2019-07-15 15:07:25.208 DEBUG 29145 --- [nio-8080-exec-1] o.s.w.s.DispatcherServlet : Exiting from "ERROR" dispatch, status 404 Here is my project structure: FooApplication ├── build.gradle ├── api/ ├── src.main.java.com.foo/ ├── FooApplication.java └── build.gradle ├── web/ ├── node_modules/ ├── src.main.webapp/ ├── app/ ├── index.tsx ├── routes.tsx └── app.tsx └── index.html ├── webpack/ └── webpack.common.js └── build.gradle Here my webpack.common.js file: const webpack = require('webpack'); const {BaseHrefWebpackPlugin} = require('base-href-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); const path = require('path'); const utils = require('./utils.js'); const getTsLoaderRule = env => { const rules = [ { loader: 'cache-loader', options: { cacheDirectory: path.resolve('build/cache-loader') } }, { loader: 'thread-loader', options: { // There should be 1 cpu for the fork-ts-checker-webpack-plugin. // The value may need to be adjusted (e.g. to 1) in some CI environments, // as cpus() may report more cores than what are available to the build. workers: require('os').cpus().length - 1 } }, { loader: 'ts-loader', options: { transpileOnly: true, happyPackMode: true } } ]; if (env === 'development') { rules.unshift({ loader: 'react-hot-loader/webpack' }); } return rules; }; module.exports = options => ({ cache: options.env !== 'production', resolve: { extensions: [ '.js', '.jsx', '.ts', '.tsx', '.json' ], modules: ['node_modules'], alias: { app: utils.root('src/main/webapp/app/') } }, module: { rules: [ { test: /\.tsx?$/, use: getTsLoaderRule(options.env), include: [utils.root('./src/main/webapp/app')], exclude: [utils.root('node_modules')] }, { test: /\.(jpe?g|png|gif|svg|woff2?|ttf|eot)$/i, loader: 'file-loader', options: { digest: 'hex', hash: 'sha512', name: 'content/[hash].[ext]' } }, { enforce: 'pre', test: /\.jsx?$/, loader: 'source-map-loader' }, { test: /\.tsx?$/, enforce: 'pre', loader: 'tslint-loader', exclude: [utils.root('node_modules')] } ] }, stats: { children: false }, optimization: { splitChunks: { cacheGroups: { commons: { test: /[\\/]node_modules[\\/]/, name: 'vendors', chunks: 'all' } } } }, plugins: [ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: `'${options.env}'`, VERSION: `'${utils.parseVersion()}'`, DEBUG_INFO_ENABLED: options.env === 'development', // The root URL for API calls, ending with a '/' - for example: `"https://www.jhipster.tech:8081/myservice/"`. // If this URL is left empty (""), then it will be relative to the current context. // If you use an API server, in `prod` mode, you will need to enable CORS // (see the `jhipster.cors` common JHipster property in the `application-*.yml` configurations) SERVER_API_URL: `''` } }), new ForkTsCheckerWebpackPlugin({tslint: true}), new CopyWebpackPlugin([ {from: './node_modules/swagger-ui/dist/css', to: 'swagger-ui/dist/css'}, {from: './node_modules/swagger-ui/dist/lib', to: 'swagger-ui/dist/lib'}, {from: './node_modules/swagger-ui/dist/swagger-ui.min.js', to: 'swagger-ui/dist/swagger-ui.min.js'}, {from: './src/main/webapp//swagger-ui/', to: 'swagger-ui'}, {from: './src/main/webapp/static/', to: 'content'}, {from: './src/main/webapp/favicon.ico', to: 'favicon.ico'}, {from: './src/main/webapp/manifest.webapp', to: 'manifest.webapp'}, // jhipster-needle-add-assets-to-webpack - JHipster will add/remove third-party resources in this array {from: './src/main/webapp/robots.txt', to: 'robots.txt'} ]), new HtmlWebpackPlugin({ template: './src/main/webapp/index.html', chunksSortMode: 'dependency', inject: 'body' }), new BaseHrefWebpackPlugin({baseHref: '/'}), ] }); How do I get spring boot to serve up the index.html file when navigating to localhost:8080? I know I'm going to have to override some default spring boot configurations to get this to work but I'm not clear on what configurations. I can provide details of any more files upon request, just didn't want to overload the post with unnecessary info.
Request mapping for your application's entry point, read the file, and return the content. In my case, the React code is stored at /tmp/build/index.html. Simplified and ignoring errors, it might look something like this: #RequestMapping( value = "", method = RequestMethod.GET) public ResponseEntity<String> getIndexContent() { final File file = new File("/tmp/build/index.html"); final String content = FileUtils.readFileToString( file, StandardCharsets.UTF_8); return ResponseEntity .ok() .contentType(MediaType.TEXT_HTML) .body(content); }
Spring-boot auto-configures some paths by default as static resource locations: /static, /public or /resources. See the Official Spring Docs So if you can move your index.html and dependent assets into the static resource paths, Spring Boot should serve them as-is. Alternatively, as those same docs say, you could add new paths as a static locations by setting the spring.resources.static-locations property. A nice thing to do would be to build your React application, bundling the resources, and copying the bundled assets + index.html to the Spring project's static location. You haven't mentioned anything about your build setup, if you're using the Gradle Node Plugin with Webpack, then this shouldn't be hard. This blog post shows how you'd do that (however, not using multiple modules)
how to fix 'resource not found' when trying to download file in spring boot REST API?
I'm new to spring framework and REST, and now trying to migrate REST from jersey to spring boot 2.1 The controller works fine with jax-rs, however, I don't want to use jax-rs in spring boot. So, I tried spring Mvc and I get 'resource not found' error. Please I'd really appreciate any help. I tried this #GetMapping(value ="/generic/download_file/{path:[^\\.+]*}", consumes ="application/vnd.X-FileContent") public ResponseEntity<?> downloadFile(#PathVariable("path") String filePath){ String actualFilePath = ""; try { actualFilePath = filePath.replaceAll("\\/", "\\\\"); File file = new File(actualFilePath); if (file.exists()) { return ResponseEntity.ok().header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"").body(file); } else { return errorHandling.errorResponseFactory("1.0.0", Thread.currentThread().getStackTrace()[1], "", RecommendedSolution.UseValidDirectoryPath, "File not exist."); } } catch (Exception ex) { ActionLog.writeLog("program_library_v510", "1.0.0", "Exception occur during gettig generic package file", ActionLogType.DebugLog); ActionLog.writeLog("program_library_v510", "1.0.0", "Exception occur during getting generic package file", ActionLogType.ErrorLog); return errorHandling.errorResponseFactory("1.0.0", Thread.currentThread().getStackTrace()[1], "", RecommendedSolution.UnexpectedErrorMsg, ""); } } 2019-01-07 17:17:23.930 INFO 13664 --- [nio-9090-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 10 ms 2019-01-07 17:17:23.947 DEBUG 13664 --- [nio-9090-exec-2] o.s.web.servlet.DispatcherServlet : GET "/packages/download_file/D:/xfolder/test.txt", paramete rs={} 2019-01-07 17:17:24.002 DEBUG 13664 --- [nio-9090-exec-2] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/ resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"] 2019-01-07 17:17:24.006 DEBUG 13664 --- [nio-9090-exec-2] o.s.w.s.r.ResourceHttpRequestHandler : Resource not found 2019-01-07 17:17:24.007 DEBUG 13664 --- [nio-9090-exec-2] o.s.web.servlet.DispatcherServlet : Completed 404 NOT_FOUND 2019-01-07 17:17:24.015 DEBUG 13664 --- [nio-9090-exec-2] o.s.web.servlet.DispatcherServlet : "ERROR" dispatch for GET "/error", parameters={} 2019-01-07 17:17:24.029 DEBUG 13664 --- [nio-9090-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServ letRequest) 2019-01-07 17:17:24.077 DEBUG 13664 --- [nio-9090-exec-2] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Using 'application/json', given [/] and supported [applic ation/json, application/+json, application/json, application/+json] 2019-01-07 17:17:24.078 DEBUG 13664 --- [nio-9090-exec-2] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Writing [{timestamp=Mon Jan 07 17:17:24 SGT 2019, status=40 4, error=Not Found, message=No message available, path=/packages/download_file/D:/xfolder/test.txt}] 2019-01-07 17:17:24.146 DEBUG 13664 --- [nio-9090-exec-2] o.s.web.servlet.DispatcherServlet : Exiting from "ERROR" dispatch, status 404
I suspect two things here. Let me clarify this. What is the API url you are calling? /generic/download_file/{path:[^\\.+]*} or /packages/download_file/D:/xfolder/test.txt both are looks different. Please see generic and packages The better way to pass filenames in URL is using #RequestParam instead of #PathVariable #GetMapping(value ="/generic/download_file/", consumes ="application/vnd.X-FileContent") public ResponseEntity downloadFile(#RequestParam("path") String filePath){
Flux subscribed through SSE raise a cancel() event
I have a Spring Boot 2.0.0.M7 + Spring Webflux application in which I am using Thymeleaf Reactive. I noticed that on my microservices, when I call an endpoint returning a flux of data in SSE mode (text/event-stream), a cancel() occurs on this flux even if it has been processed correctly. For example, here's a simple controller endpoint: #GetMapping(value = "/posts") public Flux<String> getCommunityPosts() { return Flux.just("A", "B", "C").log("POSTS"); } And here's the subscribed flux logs I get when I request it in SSE mode: 2018-02-13 17:04:09.841 INFO 4281 --- [nio-9090-exec-4] POSTS : | onSubscribe([Synchronous Fuseable] FluxArray.ArraySubscription) 2018-02-13 17:04:09.841 INFO 4281 --- [nio-9090-exec-4] POSTS : | request(1) 2018-02-13 17:04:09.842 INFO 4281 --- [nio-9090-exec-4] POSTS : | onNext(A) 2018-02-13 17:04:09.847 INFO 4281 --- [nio-9090-exec-4] POSTS : | request(1) 2018-02-13 17:04:09.847 INFO 4281 --- [nio-9090-exec-4] POSTS : | onNext(B) 2018-02-13 17:04:09.848 INFO 4281 --- [nio-9090-exec-4] POSTS : | request(1) 2018-02-13 17:04:09.848 INFO 4281 --- [nio-9090-exec-4] POSTS : | onNext(C) 2018-02-13 17:04:09.849 INFO 4281 --- [nio-9090-exec-4] POSTS : | request(1) 2018-02-13 17:04:09.849 INFO 4281 --- [nio-9090-exec-4] POSTS : | onComplete() 2018-02-13 17:04:09.852 INFO 4281 --- [nio-9090-exec-4] POSTS : | cancel() We can notice the cancel event after the onComplete. I don't have this behaviour when I call the same endpoint through a classic GET request. I suspect this cancel event to make the client side event source (javascript) throw a onError event. Is it a known/wanted behaviour specific to SSE? QUESTION UPDATE I actually use SSE on some of my streams because I sometimes need my event sources to get JSON data instead of HTML already processed by Thymeleaf. Should I do it in another way? I based my implementation on the last method of this example: https://github.com/danielfernandez/reactive-matchday/blob/master/src/main/java/com/github/danielfernandez/matchday/web/controller/MatchController.java However, I may have missed providing some information in my previous post. I use Tomcat Server (8.5.23 with M7), and not Netty server. I forced Tomcat use including the following Maven dependency: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </dependency> Using your code on a sample project, this seems to cause the issue. When I run the code on a Netty server, I get the same results as you: 2018-02-14 12:30:48.713 INFO 3060 --- [ctor-http-nio-2] reactor.Flux.ConcatMap.1 : onSubscribe(FluxConcatMap.ConcatMapImmediate) 2018-02-14 12:30:48.714 INFO 3060 --- [ctor-http-nio-2] reactor.Flux.ConcatMap.1 : request(1) 2018-02-14 12:30:49.717 INFO 3060 --- [ parallel-2] reactor.Flux.ConcatMap.1 : onNext(a) 2018-02-14 12:30:49.739 INFO 3060 --- [ctor-http-nio-2] reactor.Flux.ConcatMap.1 : request(31) 2018-02-14 12:30:50.731 INFO 3060 --- [ parallel-3] reactor.Flux.ConcatMap.1 : onNext(b) 2018-02-14 12:30:51.733 INFO 3060 --- [ parallel-4] reactor.Flux.ConcatMap.1 : onNext(c) 2018-02-14 12:30:51.735 INFO 3060 --- [ parallel-4] reactor.Flux.ConcatMap.1 : onComplete() When I run the same code on the Tomcat server, I have the cancel issue: 2018-02-14 12:33:18.294 INFO 3088 --- [nio-8080-exec-3] reactor.Flux.ConcatMap.2 : onSubscribe(FluxConcatMap.ConcatMapImmediate) 2018-02-14 12:33:18.295 INFO 3088 --- [nio-8080-exec-3] reactor.Flux.ConcatMap.2 : request(1) 2018-02-14 12:33:19.295 INFO 3088 --- [ parallel-4] reactor.Flux.ConcatMap.2 : onNext(a) 2018-02-14 12:33:19.297 INFO 3088 --- [ parallel-4] reactor.Flux.ConcatMap.2 : request(1) 2018-02-14 12:33:20.302 INFO 3088 --- [ parallel-5] reactor.Flux.ConcatMap.2 : onNext(b) 2018-02-14 12:33:20.302 INFO 3088 --- [ parallel-5] reactor.Flux.ConcatMap.2 : request(1) 2018-02-14 12:33:21.306 INFO 3088 --- [ parallel-6] reactor.Flux.ConcatMap.2 : onNext(c) 2018-02-14 12:33:21.306 INFO 3088 --- [ parallel-6] reactor.Flux.ConcatMap.2 : request(1) 2018-02-14 12:33:21.307 INFO 3088 --- [ parallel-6] reactor.Flux.ConcatMap.2 : onComplete() 2018-02-14 12:33:21.307 INFO 3088 --- [nio-8080-exec-4] reactor.Flux.ConcatMap.2 : cancel() Could it be a Tomcat issue or am I doing something wrong?
First, I don't think you should use SSE for finite streams. When I create a Controller method like: #GetMapping(path = "/test", produces = MediaType.TEXT_EVENT_STREAM_VALUE) #ResponseBody public Flux<String> test() { return Flux.just("a", "b", "c").delayElements(Duration.ofSeconds(1)).log(); } and request it from a browser (Chrome or Firefox) with: <script type="text/javascript"> var testEventSource = new EventSource("/test"); testEventSource.onmessage = function (e) { console.log(e); }; </script> I get the following logs on the server: | onSubscribe([Fuseable] FluxOnAssembly.OnAssemblySubscriber) | request(1) | onNext(a) | request(31) | onNext(b) | onNext(c) | onComplete() | onSubscribe([Fuseable] FluxOnAssembly.OnAssemblySubscriber) | request(1) | onNext(a) | request(31) | onNext(b) | onNext(c) | onComplete() As soon as the Flux is completed, the connection is closed by the server and the browser reconnects automatically. This will replay the same sequence over and over again. The only way I get a cancel() event on the server is when I close the browser tab during the stream.
Attempting two pass two objects through #PathVariable in thymeleaf/spring-boot
I'm attempting to pull two parameters with the #PathVariable annotation but have been unsuccessful due to java throwing me an error about it referencing the item id (which I currently has as an Long) as a String. Controller: #PostMapping("/purchaseToner/{tid}/{bid}") public String buyToner(Model model, #PathVariable("tid") Long tid, #PathVariable("bid") Long bid){ //Grab info Buyer mBuyer = buyerService.findOne(bid); Toner mToner = tonerService.findOneToner(tid); //Updating qualities mToner.setTonerQuantity(mToner.getTonerQuantity() - 1); mBuyer.setBalance(mBuyer.getBalance() - mToner.getTonerPrice()); Buyer iBuyer = new Buyer(); iBuyer.getToners().add(mToner); return "redirect:/"; } View: <form th:action="#{/purchaseToner/{tid}(tid=${toner.id})/{bid}(bid=${buyer.buyerId})}" th:object="${buyer}" method="post"> <select th:object="${toner}"> <option>Select a Toner</option> <option th:each="toner : ${toners}" th:text="${toner.tonerName}" th:value="${toner.id}"> </option> </select> <input type="hidden" name="buyerId"/> <input type="submit" value="Purchase" onclick="return confirm('Are you sure you want to make this purchase?')"/> </form> Print Trace: 2017-06-05 21:10:59.418 INFO 788 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup 2017-06-05 21:10:59.517 INFO 788 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http) 2017-06-05 21:10:59.527 INFO 788 --- [ main] com.ronone.Application : Started Application in 18.596 seconds (JVM running for 19.548) 2017-06-05 21:11:06.438 INFO 788 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet' 2017-06-05 21:11:06.439 INFO 788 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started 2017-06-05 21:11:06.470 INFO 788 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 31 ms 2017-06-05 21:11:09.673 INFO 788 --- [nio-8080-exec-2] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory 2017-06-05 21:11:15.837 WARN 788 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to bind request element: org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'; nested exception is java.lang.NumberFormatException: For input string: "{tid}(tid=${toner.id})"
Your api buyToner has not been receiving inputs in path variable as number. There is nothing wrong with your api service; check your client side code, is it sending request in proper format OR have you tested your api with any restclient ? Check out the java exception java.lang.NumberFormatException: For input string: "{tid}(tid=${toner.id})" input is not a number here. AND WHY ?
Try to change this: #PostMapping("/purchaseToner/{tid}/{bid}") public String buyToner(Model model, #PathVariable("tid") Long tid, #PathVariable("bid") Long bid){ ... } into this: #PostMapping("/purchaseToner/{tid}/{bid}") public String buyToner(Model model, #PathVariable("tid") String tid, #PathVariable("bid") String bid){ long bidlong = Long.parseLong(bid) long tidlong = Long.parseLong(tid) //Grab info Buyer mBuyer = buyerService.findOne(bid); Toner mToner = tonerService.findOneToner(tid); ... } In other words, change your controller's parameters into String types, then convert them into Long.
Change th:action to following <form th:action="#{/purchaseToner/{tid}/{bid}(tid=${toner.id},bid=${buyer.buyerId})}" th:object="${buyer}" method="post"> Also, you need to add toner to spring model. In your code, It is not in the model