Broadcasts in the atmosphere do not reach the client when working in Tomcat

Significant update below (October 15, 2014)

========== Original publication ====================

I have a notification support service using Atmosphere and Jersey. I am trying to run it on Tomcat on Linux and am facing a problem. (Note that this works fine when run in Tomcat-embedded-in-Eclipse, so this may become a Tomcat configuration problem.)

The problem is that the broadcast messages appear in the queue or are buffered and are not actually delivered to the client until I turn off Tomcat. At this moment, they are all accepted by the client immediately.

I tried several things that I found in different publications to try to solve this problem, but my efforts split because I do not know what causes the problem:

  • I tried explicitly using the Tomcat NIO protocol.
  • I tried to explicitly disable text and binary buffering, and I also queued enough responses to trigger a flash if buffering was the cause.
  • I tried working in Tomcat 8 instead (but it had different unrelated problems.)
  • I added an atmosphere and environment dependent environment, atmosphere-compat-jbossweb and atmosphere-compatibility-cat.

None of them changed the behavior of the service. And, again, it seems to work just fine when working in Eclipse.

Environment: Ubuntu 14.04 LTS. Tomcat 7.0.54. Atmosphere 2.1.5. For the client, I just use telnet at the moment.

(This code is a bit more complicated than the samples, because I have several different routes that I want to support, and I use the method suggested by this Answer, which seems to work well. I also return notification objects, not strings. This also seems to work fine. I just stripped most of the authentication elements.)

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.clearcaptial</groupId> <artifactId>notifications</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>notifications Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>org.atmosphere</groupId> <artifactId>atmosphere-jersey</artifactId> <version>2.1.5</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-json</artifactId> <version>1.17.1</version> </dependency> <dependency> <groupId>org.atmosphere</groupId> <artifactId>atmosphere-runtime-native</artifactId> <version>2.1.5</version> </dependency> <dependency> <groupId>org.atmosphere</groupId> <artifactId>atmosphere-compat-jbossweb</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>org.atmosphere</groupId> <artifactId>atmosphere-compat-tomcat</artifactId> <version>2.0.1</version> </dependency> </dependencies> <build> <finalName>notifications</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build> </project> 

web.xml:

 <?xml version="1.0" encoding="UTF-8"?> <!-- This web.xml file is not required when using Servlet 3.0 container, see implementation details http://jersey.java.net/nonav/documentation/latest/jax-rs.html --> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:j2ee="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_3.0.xsd"> <servlet> <servlet-name>AtmosphereServlet</servlet-name> <servlet-class>org.atmosphere.cpr.AtmosphereServlet</servlet-class> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>com.clearcapital.notifications</param-value> </init-param> <init-param> <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>org.atmosphere.useWebSocketAndServlet3</param-name> <param-value>true</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>AtmosphereServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app> 

from ValidationsRouter.java:

 @Path("/validations") public class ValidationsRouter { @Context private AtmosphereResource atmosphereResource; @GET public SuspendResponse<ValidationNotification> subscribe(@Context UriInfo uri) throws URISyntaxException, NamingException, IOException { return new ValidationsResource().subscribe(uri, atmosphereResource); } @Broadcast @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Broadcastable broadcast(ValidationNotification message, @Context UriInfo uri) { return new ValidationsResource().broadcast(message, uri); } } 

from ValidationsResource.java:

 public class ValidationsResource extends ResourceBase<ValidationNotification> { // a bunch of authentication stuff omitted for clarity. } 

from ResourceBase.java:

 public abstract class ResourceBase<T> { public SuspendResponse<T> subscribe(UriInfo uri, AtmosphereResource atmosphereResource) throws URISyntaxException, NamingException, IOException { Broadcaster myBroadcaster = BroadcasterFactory.getDefault().lookup(uri.getPath(), true); return new SuspendResponse.SuspendResponseBuilder<T>().broadcaster(myBroadcaster).outputComments(true) .addListener(new EventsLogger()).type(MediaType.APPLICATION_JSON_TYPE).build(); } public Broadcastable broadcast(T message, UriInfo uri) { Broadcaster myBroadcaster = BroadcasterFactory.getDefault().lookup(uri.getPath(), true); return new Broadcastable(message, "", myBroadcaster); } } 

============= End of original message =======================

Updated on October 15, 2014:

I returned to this problem after a while in another project. After updating the project with the new version of the Atmosphere (2.2.3), I see no difference in behavior. It still remains that when the service starts on a different computer than the client is running, atmosphere broadcasts are not received by the client until Tomcat disconnects. When you start the client and the service on the same computer, everything works as expected.

So, to determine where the problem lies, I started using only one of the Atmosphere app's applications in my testing. I am using the jersey-pubsub example application (with minor updates to compile it) because the one that is closest to what I'm trying to do. I created a completely new server environment to run a sample application to minimize any variables based on Linux configuration. Here are the new steps - maybe someone can reproduce the behavior.

To get a new server with Tomcat7 installed (I use Vagrant and VirtualBox for these tests):

 host$ vagrant init ubuntu/trusty64 host$ nano Vagrantfile 

change the network configuration to a known IP: config.vm.network :private_network, ip: "10.1.1.2"

 host$ vagrant box add https://vagrantcloud.com/ubuntu/boxes/trusty64/versions/1/providers/virtualbox.box host$ vagrant up ------------------ vagrant$ sudo apt-get update vagrant$ sudo apt-get upgrade vagrant$ sudo apt-get install tomcat7 

Following these steps, I ended up with Tomcat 7.0.52 and Ubuntu 14.04

I have a copy of a jersey-pubsub project (without a parent project, etc.) that I create with

 host$ mvn clean install 

and then expand

 host$ cp target/jersey-pubsub.war ../../vagrants/trusty64/ vagrant$ sudo cp /vagrant/jersey-pubsub.war /var/lib/tomcat7/webapps 

Then I can check this with telnet, for example:

 host$ telnet 10.1.1.2 8080 <return> GET /jersey-pubsub/pubsub/foo HTTP/1.0 <return> <return> 

At this point, telnet continues to wait for data. In the tomcat server log I see an entry:

 20:33:55.805 [http-bio-8080-exec-1] INFO oasamples.pubsub.EventsLogger - onSuspend(): 10.1.1.1:59357 

Then I send a POST request to the server. I use POSTman for this, but I do not think this is important.

 POST http://10.1.1.2:8080/jersey-pubsub/pubsub/foo Accept: text/html Content-Type: application/x-www-form-urlencoded message: <html><body><p>This is a test!</p></body></html> 

In the server log, I see that the server believes that it is sending a message:

 20:34:06.990 [Atmosphere-Shared-AsyncOp-0] INFO oasamples.pubsub.EventsLogger - onBroadcast(): <html><body><p>This is a test!</p></body></html> 

but nothing is displayed in the telnet client. I can repeat infinity and see no result until I turn off Tomcat, after which all broadcast messages will be immediately sent to Telnet.

In contrast, if I deploy the service on a tomcat instance running on the host machine, or if I run telnet inside the vagrant instance, everything works as expected:

 vagrant$ telnet localhost 8080 <return> GET /jersey-pubsub/pubsub/foo HTTP/1.0 <return> <return> 

If I then send the same POST request, I immediately receive a broadcast message in telnet. The behavior seems to be that if the service and the client are not on the same computer, then network traffic is held back while Tomcat is running.

Here is the source code for my copy of the jersey-pubsub sample, with enough changes to make it compile and build as a separate project.

EventsLogger.java: (No change, except to remove @Override in 2 places to make Eclipse stop complaining)

FileResource.java: (No change)

JerseyPubSub.java: (no change)

web.xml: (No change)

pom.xml (modified to create as standalone, without reference to the parent pom):

 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.atmosphere.samples</groupId> <artifactId>atmosphere-jersey-pubsub</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>atmosphere-jersey-pubsub</name> <url>http://maven.apache.org</url> <properties> <atmosphere-version>2.2.3</atmosphere-version> <client-version>2.2.3</client-version> <logback-version>1.0.13</logback-version> </properties> <repositories> <repository> <id>oss.sonatype.org</id> <url>http://oss.sonatype.org/content/repositories/releases</url> </repository> <repository> <id>oss.sonatype.org-snapshot</id> <url>http://oss.sonatype.org/content/repositories/snapshots</url> </repository> <!-- <repository> <id>scala-tools.org</id> <name>Scala-Tools Maven2 Repository</name> <url>http://scala-tools.org/repo-releases</url> </repository> --> <repository> <id>jboss</id> <url>https://repository.jboss.org/nexus/content/groups/public/</url> </repository> <repository> <id>codehaus</id> <name>repository.codehaus.org</name> <url>http://repository.codehaus.org</url> </repository> <repository> <id>codehaus-snapshots</id> <url>http://snapshots.repository.codehaus.org</url> </repository> <repository> <id>maven.java.net</id> <url>https://maven.java.net/content/groups/public/</url> </repository> </repositories> <dependencyManagement> <dependencies> <dependency> <groupId>org.atmosphere</groupId> <artifactId>atmosphere-runtime</artifactId> <version>${atmosphere-version}</version> </dependency> <dependency> <groupId>org.apache.geronimo.specs</groupId> <artifactId>geronimo-servlet_3.0_spec</artifactId> <version>1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback-version}</version> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.atmosphere.client</groupId> <artifactId>javascript</artifactId> <version>${client-version}</version> <type>war</type> </dependency> <dependency> <groupId>org.atmosphere</groupId> <artifactId>atmosphere-jersey</artifactId> <version>${atmosphere-version}</version> </dependency> <dependency> <groupId>org.apache.geronimo.specs</groupId> <artifactId>geronimo-servlet_3.0_spec</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>${logback-version}</version> </dependency> </dependencies> <build> <finalName>jersey-pubsub</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build> </project> 
+6
source share
3 answers

Returning to this problem after a few months, I was able to understand why I observed this behavior: it was the built-in telnet client for Mac that behaved badly. I confirmed that the responses were recorded immediately when using telnet from Windows or Linux, and I also tested another telnet client for Mac, and it also behaved as expected. Although I worked with him for a while, I was not able to find out if there are any tel-theta that I could point to on the Mac, so that it behaves the way it was on Linux with which I tested.

+1
source
  • Do you use tomcat behind apache proxy?
  • Is apache HTTP 1.1 running?
  • A few more Apaches to try here
+1
source

Take a look at the quick dependency checklist below on this page.

Make sure you have the right banks on the class path for the specific tomcat version you are using.

See my pom.xml here , where I have a profile with several container options.

Try running mvn dependency:tree from the command line. Perhaps the atmosphere-knitwear brings the atmosphere-time as a transitive relationship. In this case, you will want to exclude it for tomcat 7.

0
source

Source: https://habr.com/ru/post/971067/


All Articles