After looking at the logs, I see that when I run my application, it starts a TomCat WebServer
SpringApplication.run(SampleApplication.class, args);
Logs:
main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8081 (http) with context path
Currently, I have metrics being exposed to a /metrics endpoint and different port. This is done by creating a new Server like this:
SpringApplication.run(SampleApplication.class, args);
try {
Server server = new Server(8080);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server.setHandler(context);
context.addServlet(new ServletHolder(new MetricsServlet()), "/metrics");
server.start();
server.join();
Logs:
STARTED #2880ms ManagedSelector#2f953efd{STARTED} id=1 keys=0 selected=0 updates=0
Selector sun.nio.ch.WindowsSelectorImpl#71a81a3e waiting with 0 keys
STARTED #2880ms SelectorManager#ServerConnector#550ee7e5{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
ServerConnector#550ee7e5{HTTP/1.1, (http/1.1)}{0.0.0.0:8080} added {acceptor-0#13526e59,POJO}
Started ServerConnector#550ee7e5{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
run acceptor-0#13526e59 in QueuedThreadPool[qtp1437654187]#55b0dcab{STARTED,8<=8<=200,i=5,r=-1,q=0}
[ReservedThreadExecutor#74e28667{reserved=0/4,pending=0}]
10:44:35.454 [main] DEBUG org.eclipse.jetty.util.component.AbstractLifeCycle - STARTED #2882ms ServerConnector#550ee7e5{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
10:44:35.455 [main] INFO org.eclipse.jetty.server.Server - Started Server#3e96bacf{STARTING}[11.0.9,sto=0] #2887ms
10:44:35.455 [main] DEBUG org.eclipse.jetty.util.component.AbstractLifeCycle - STARTED #2887ms Server#3e96bacf{STARTED}[11.0.9,sto=0]
The problem is, I want to access the initial TomCat Webserver and add the ServletHolder to it (therefore exposing metrics endpoint but by linking it to tomcat webserver).
I guess my question is, can it be done this way and is it a good practice?
I've tried creating a #GetMapping("/metrics") endpoint within my SampleApplication, but I couldn't add the MetricsServlet that way
Related
I've developed a Spring application that uses STOMP Server, and I would like to shutdown the STOMP server programmatically.
I've tried to shutdown the application using the following code:
SpringApplication.exit(context, new ExitCodeGenerator() {
#Override
public int getExitCode() {
return 0;
}
});
However, the code produces the following error:
...
WARN 15444 --- [ main] o.a.c.loader.WebappClassLoaderBase : The web application [ROOT] appears to have started a thread named [MessageBroker-4] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
java.base/jdk.internal.misc.Unsafe.park(Native Method)
...
To avoid the error, my plan is to shutdown the STOMP server first and then execute the
SpringApplication.exit( ... )
So, my question is how to shutdown the STOMP server programmatically?
Probably, the code should produce output like this one:
2023-01-13 20:28:05.869 INFO 4380 --- [ionShutdownHook] o.s.m.s.b.SimpleBrokerMessageHandler : Stopping...
2023-01-13 20:28:05.870 INFO 4380 --- [ionShutdownHook] o.s.m.s.b.SimpleBrokerMessageHandler : BrokerAvailabilityEvent[available=false, SimpleBrokerMessageHandler [org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry#5d68db92]]
2023-01-13 20:28:05.870 INFO 4380 --- [ionShutdownHook] o.s.m.s.b.SimpleBrokerMessageHandler : Stopped.
I'm running an application with Spring (as Discovery Client app), also have a Discovery Server with Eureka, and Spring Cloud Config Server. When the client app is started it's registered as "UNKNOWN" in Eureka, despite its status is set to"UP", isn't able to get the properties from the configuration server.
Client App, Eureka server,and Config Server Spring Boot Version: 2.4.2
Client bootstrap.properties:
spring.application.name=config-client-app
spring.cloud.config.discovery.enabled=true
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
eureka.instance.instance-id=${spring.application.name}
Client application.properties file:
logging.level.=debug
server.port=8900
eureka.client.healthcheck.enabled=true
Client Application Class:
#SpringBootApplication
#EnableDiscoveryClient
#RestController
public class ConfigClientAppApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientAppApplication.class, args);
}
}
Eureka Serverproperties file:
spring.application.name=discovery-server
server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
Eureka Application class:
#EnableEurekaServer
#SpringBootApplication
public class DiscoveryServerApplication {
public static void main(String[] args) {
SpringApplication.run(DiscoveryServerApplication.class, args);
}
}
The log info:
restartedMain] c.n.discovery.InstanceInfoReplicator : InstanceInfoReplicator onDemand update allowed rate per min is 4
2021-02-09 16:02:50.388 INFO 2845 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : Discovery Client initialized at timestamp 1612904570388 with initial instances count: 1
2021-02-09 16:02:50.390 INFO 2845 --- [ restartedMain] o.s.c.n.e.s.EurekaServiceRegistry : Registering application UNKNOWN with eureka with status UP
2021-02-09 16:02:50.391 INFO 2845 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : Saw local status change event StatusChangeEvent [timestamp=1612904570391, current=UP, previous=STARTING]
2021-02-09 16:02:50.391 INFO 2845 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_UNKNOWN/192.168.10.22:8900: registering service...
2021-02-09 16:02:50.391 WARN 2845 --- [ restartedMain] c.n.discovery.InstanceInfoReplicator : Ignoring onDemand update due to rate limiter
2021-02-09 16:02:50.393 INFO 2845 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8900 (http) with context path ''
2021-02-09 16:02:50.394 INFO 2845 --- [ restartedMain] .s.c.n.e.s.EurekaAutoServiceRegistration : Updating port to 8900
2021-02-09 16:02:50.413 INFO 2845 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_UNKNOWN/192.168.10.22:8900 - registration status: 204
I am using Spring cloud version
<spring-cloud.version>2021.0.5</spring-cloud.version>
and spring boot version
<version>2.7.5</version>
In application.properties, add the following lines to resolve the error:
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
By default, the Eureka Server registers itself into the discovery. The following 2 lines will tell eureka server that there is only one eureka server present in this context.
in the absence of these, our Eureka Server will try to find and register itself on other Eureka Servers in the context and throw a discovery client exception. i.e our own system.
If you encounter the below errors after adding the above properties only you need to add the below properties.
We must add this to the properties, if configuration is not required.
spring.cloud.config.enabled=false
Otherwise application will throw below exception.
No spring.config.import property has been defined
(or) If you have a other server, such as any configuration server we can add this optional server configuration to application.properties,
spring.config.import=optional:configserver: Your server url
Spring Cloud Config provides server and client-side support for
externalized configuration in a distributed system
I am new to EJB as well as Geronimo server.
I want to create Junit POC for EJB on Geronimo Server.
But on Lookup to Stateless Session bean its giving me this error.
Please find the exception below
javax.naming.NamingException: Cannot lookup '/MyStatelessSessionBeanRemote'. [Root exception is java.rmi.RemoteException: Cannot read the response from the server. The class for an object being returned is not located in this system:; nested exception is:
java.lang.ClassNotFoundException: sampleear.RemoteBusinessInterface]
at org.apache.openejb.client.JNDIContext.lookup(JNDIContext.java:240)
at javax.naming.InitialContext.lookup(InitialContext.java:363)
at test.SampleTest.setUp(SampleTest.java:44)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
I am using Geronimo server 2.1 and I have also deployed the EAR file in geronimo server.
EAR file gets successfully deployed showing on the Geronimo server.
Please find the Logs below
2019-07-01 14:39:46,221 INFO [config] Configuring Service(id=Default BMP Container, type=Container, provider-id=Default BMP Container)
2019-07-01 14:39:46,222 INFO [config] Configuring Service(id=Default CMP Container, type=Container, provider-id=Default CMP Container)
2019-07-01 14:39:46,222 INFO [config] Configuring app: sampleear/sample-ejb/1.0/ejb
2019-07-01 14:39:46,269 INFO [OpenEJB] Auto-deploying ejb MyStatelessSessionBean: EjbDeployment(deployment-id=sample-ejb/MyStatelessSessionBean)
2019-07-01 14:39:46,277 INFO [config] Loaded Module: sampleear/sample-ejb/1.0/ejb
2019-07-01 14:39:46,555 INFO [startup] Assembling app: /tmp/geronimo-deployer1011310413181662917.tmpdir/SampleEJB.jar
2019-07-01 14:39:46,557 ERROR [startup] Jndi(name=MyStatelessSessionBeanRemote) cannot be bound to Ejb(deployment-id=sample-ejb/MyStatelessSessionBean). Name already taken by Ejb(deployment-id=SampleEJB.jar/MyStatelessSessionBean)
2019-07-01 14:39:46,557 INFO [startup] Created Ejb(deployment-id=sample-ejb/MyStatelessSessionBean, ejb-name=MyStatelessSessionBean, container=Default Stateless Container)
2019-07-01 14:39:46,558 INFO [startup] Deployed Application(path=/tmp/geronimo-deployer1011310413181662917.tmpdir/SampleEJB.jar)
2019-07-01 14:39:46,673 INFO [SupportedModesServiceImpl] Portlet mode 'edit' not found for portletId: '/plugin.Deployment!227983155|0'
2019-07-01 14:39:46,676 INFO [XSRFHandler] Updated HTML content with XSRF JavaScript for requestURI=/console/portal//Applications/Deploy%20New
Junit - Client
public class SampleTest extends TestCase {
protected MyStatelessSessionBean remoteBusinessIntf;
public void setUp() throws Exception {
super.setUp();
Properties prop = new Properties();
prop.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.RemoteInitialContextFactory");
prop.put("java.naming.provider.url", "ejbd://127.0.0.1:4201");
// prop.put("openejb.authentication.realmName","geronimo-admin");
// prop.put("java.naming.security.principal","system");
// prop.put("java.naming.security.credentials","manager");
Context context = new InitialContext(prop);
remoteBusinessIntf = (MyStatelessSessionBean) context.lookup("MyStatelessSessionBeanRemote"); // Giving error on this.
}
public void testSaveBook() {
System.out.println("ok");
remoteBusinessIntf.sayHello("EJB");
}
}
Stateless Session Bean
package sampleear;
import javax.ejb.Remote;
import javax.ejb.Stateless;
#Stateless
public class MyStatelessSessionBean implements RemoteBusinessInterface {
public String sayHello(String name) {
return getClass().getName() + " says hello to "+ name + ".";
}
}
Remote Interface
package sampleear;
import javax.ejb.Remote;
#Remote
public interface RemoteBusinessInterface {
public String sayHello(String name);
}
Deployed EJB Application
Component Name State Commands
org.apache.geronimo.configs/mejb/2.1.4/car running Stop Restart Uninstall
org.apache.geronimo.plugins/agent/2.1.4/car running Stop Restart Uninstall
sampleear/sample-ejb/1.0/ejb running Stop Restart Uninstall
Geronimo v2.1.4
No Modifications to port.Default Port is used.
Port Details of Geronimo
Startup completed in 31.119s seconds
Listening on Ports:
1050 0.0.0.0 CORBA Naming Service
1099 0.0.0.0 RMI Naming
1527 0.0.0.0 Derby Connector
2001 0.0.0.0 OpenEJB ORB Adapter
4201 0.0.0.0 OpenEJB Daemon
6882 0.0.0.0 OpenEJB ORB Adapter
8009 0.0.0.0 Tomcat Connector AJP AJP
8080 0.0.0.0 Tomcat Connector HTTP BIO HTTP
8443 0.0.0.0 Tomcat Connector HTTPS BIO HTTPS
9999 0.0.0.0 JMX Remoting Connector
61613 0.0.0.0 ActiveMQ Transport Connector
61616 0.0.0.0 ActiveMQ Transport Connector
I have again created the fresh Geronimo server and deployed the EJB Application.This time haven't got any deployment error. Please find the logs below.
2019-07-02 10:28:18,242 INFO [config] Configuring Service(id=Default Stateful Container, type=Container, provider-id=Default Stateful Container)
2019-07-02 10:28:18,242 INFO [config] Configuring Service(id=Default BMP Container, type=Container, provider-id=Default BMP Container)
2019-07-02 10:28:18,242 INFO [config] Configuring Service(id=Default CMP Container, type=Container, provider-id=Default CMP Container)
2019-07-02 10:28:18,243 INFO [config] Configuring app: sampleear/sample-ejb/1.0/ejb
2019-07-02 10:28:18,275 INFO [OpenEJB] Auto-deploying ejb MyStatelessSessionBean: EjbDeployment(deployment-id=sample-ejb/MyStatelessSessionBean)
2019-07-02 10:28:18,281 INFO [config] Loaded Module: sampleear/sample-ejb/1.0/ejb
2019-07-02 10:28:18,555 INFO [startup] Assembling app: /tmp/geronimo-deployer7186189966556040174.tmpdir/SampleEJB.jar
2019-07-02 10:28:18,558 INFO [startup] Jndi(name=MyStatelessSessionBeanRemote) --> Ejb(deployment-id=sample-ejb/MyStatelessSessionBean)
2019-07-02 10:28:18,558 INFO [startup] Created Ejb(deployment-id=sample-ejb/MyStatelessSessionBean, ejb-name=MyStatelessSessionBean, container=Default Stateless Container)
2019-07-02 10:28:18,558 INFO [startup] Deployed Application(path=/tmp/geronimo-deployer7186189966556040174.tmpdir/SampleEJB.jar)
2019-07-02 10:28:18,669 INFO [SupportedModesServiceImpl] Portlet mode 'edit' not found for portletId: '/plugin.Deployment!227983155|0'
2019-07-02 10:28:18,673 INFO [XSRFHandler] Updated HTML content with XSRF JavaScript for requestURI=/console/portal//Applications/Deploy%20New
So we have Java microservices written with Spring-Boot, using Consul for service discovery and config management and running in Docker containers. All of it is working, but when a container dies or a service restarts the old service-id never goes away in Consul and the service forever after shows as "Failing" in the Consul UI, even though the new container has registered and shows all Green.
We are not using heartbeat - but I cannot find much documentation on what the difference between heartbeat and healthcheck are for Consul.
Here's my bootstrp.yml
spring:
application:
name: my-service
cloud:
config:
enabled: false
consul:
host: ${discovery.host:localhost}
port: ${discovery.port:8500}
config:
watch:
wait-time: 30
delay: 10000
profile-separator: "-"
format: FILES
discovery:
prefer-ip-address: true
instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}}
There are other settings to enable heartbeat, but the docs say something about this putting more stress on the Consul cluster.
Has anyone managed to get Consul and Spring Boot/Docker services to actually de-register automatically? It actually doesn't cause any real problems, but it makes the Consul UI pretty useless to actually monitor for up/down services.
Consul doesn't automatically deregister services.
See https://groups.google.com/forum/#!topic/consul-tool/slV5xfWRpEE for the hint about the same question. According to that thread you need to either update the config or perform an Agent API call. Since the agent is the source of truth, you shouldn't try to update via Catalog API. See GitHub for details. They also mention at the Google group that you don't necessarily have to deregister services if the node goes down gracefully, but that doesn't seem to be your use case.
Please have a look at Consul not deregistering zombie services for hints about automating the service de-registration using either the api or tools like registrator.
You have mentioned you are using a docker container to run the microservice. Are you trapping the SIGTERM in your entrypoint script in docker container ? If a SIGTERM is sent, the boot application will get it and you will see the below log showing that the microservice is deregistering with Consul.
2017-04-27 09:20:19.854 INFO 6852 --- [on(6)-127.0.0.1] inMXBeanRegistrar$SpringApplicationAdmin : Application shutdown requested.
2017-04-27 09:20:19.857 INFO 6852 --- [on(6)-127.0.0.1] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#afb5821: startup date [Thu Apr 27 09:20:00 EDT 2017]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext#130c12b7
2017-04-27 09:20:19.859 INFO 6852 --- [on(6)-127.0.0.1] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase 2147483647
2017-04-27 09:20:19.863 INFO 6852 --- [on(6)-127.0.0.1] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase 0
2017-04-27 09:20:19.863 INFO 6852 --- [on(6)-127.0.0.1] o.s.c.c.s.ConsulServiceRegistry : Deregistering service with consul: xxxxxxxxxxxxx
This blog post discusses this.
I'm trying out atmosphere on tomcat 6 but only long polling works not websockets. The message i receive in the console output is
Tomcat failed to detect this is a Comet application because context.xml is missing or the Http11NioProtocol Connector is not enabled.
Any info on this would be appreciated, thanks
Update: After modifying web.xml and server.xml the error message goes but the chat application always fallsback to long polling - I've tried several different .war deployments of websocket demos and they all behave the same.
I tried Tomcat 7 also, but it still uses long polling.
Some log info for startup
10:42:30.423 [main] INFO o.atmosphere.cpr.AtmosphereFramework - Installed Default AtmosphereInterceptor [Android Interceptor Support, SSE Interceptor Support, JSONP Interceptor Support]. Set org.atmosphere.cpr.AtmosphereInterceptor.disableDefaults in your xml to disable them.
10:42:30.423 [main] WARN o.atmosphere.cpr.AtmosphereFramework - No BroadcasterCache configured. Broadcasted message between client reconnection will be LOST. It is recommended to configure the HeaderBroadcasterCache.
10:42:30.423 [main] INFO o.atmosphere.cpr.AtmosphereFramework - HttpSession supported: false
10:42:30.423 [main] INFO o.atmosphere.cpr.AtmosphereFramework - Using BroadcasterFactory: org.atmosphere.cpr.DefaultBroadcasterFactory
10:42:30.423 [main] INFO o.atmosphere.cpr.AtmosphereFramework - Using WebSocketProcessor: org.atmosphere.websocket.DefaultWebSocketProcessor
10:42:30.423 [main] INFO o.atmosphere.cpr.AtmosphereFramework - Using Broadcaster: org.atmosphere.jersey.JerseyBroadcaster
10:42:30.428 [main] INFO o.atmosphere.cpr.AtmosphereFramework - Atmosphere Framework 1.0.0.beta5 started.
27/08/2012 10:42:30 AM org.apache.coyote.http11.Http11NioProtocol start
INFO: Starting Coyote HTTP/1.1 on http-8080
27/08/2012 10:42:30 AM org.apache.catalina.startup.Catalina start
INFO: Server startup in 11568 ms
When the chat client connects
27/08/2012 10:47:57 AM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
INFO: Using a shared selector for servlet write/read
When a message is sent
10:48:09.256 [http-8080-exec-2] DEBUG o.a.cpr.AsynchronousProcessor - Cancelling the connection for request AtmosphereRequest{ contextPath=/atmosphere-rest-chat servletPath=/chat pathInfo=null requestURI=/atmosphere-rest-chat/chat requestURL=http://mogwai:8080/atmosphere-rest-chat/chat destroyable=true}
In context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Loader delegate="true"/>
</Context>
In server.xml:
<Connector connectionTimeout="20000" port="8080"
protocol="org.apache.coyote.http11.Http11NioProtocol"
redirectPort="8443"/>
Make sure you only have one implementation of CometProcessor defined in your classpath. You may want to remove catalina.jar from your webpass if it's bundled in. See this thread for more info:
http://mail-archives.apache.org/mod_mbox/tomcat-users/200707.mbox/%3C11785700.post#talk.nabble.com%3E