java tomcat jersey atmosphere

java - Las emisiones de atmósfera no llegan al cliente cuando se ejecuta en Tomcat



jersey atmosphere (3)

  1. ¿Estás ejecutando tomcat detrás de un proxy apache?
  2. ¿Apache ejecuta HTTP 1.1?
  3. Algunas cosas más de apache para probar aquí

Actualización sustancial a continuación (15 de octubre de 2014)

========== Publicación original ===================

Tengo una aplicación web de servicio de notificación que usa Atmosphere y Jersey. Estoy tratando de ejecutarlo en Tomcat en Linux, y me he encontrado con un problema. (Tenga en cuenta que esto funciona bien cuando se ejecuta en Tomcat-embedded-within-Eclipse, por lo que es posible que se trate de un problema de configuración de Tomcat).

El problema es que los mensajes de difusión parecen estar en cola o almacenados en búfer, y realmente no se entregan al cliente hasta que apagué Tomcat. En ese momento, todos son recibidos por el cliente de una vez.

He intentado varias cosas que encontré en varias publicaciones para tratar de resolver esto, pero mis esfuerzos son dispersos porque no sé qué está causando el problema:

  • He intentado usar explícitamente el protocolo NIO de Tomcat.
  • Intenté deshabilitar explícitamente el almacenamiento en búfer de texto y binario, y también he puesto en cola las respuestas suficientes para desencadenar un enrojecimiento si la causa fue el almacenamiento en búfer.
  • Intenté ejecutar en Tomcat 8 en su lugar (pero eso tenía diferentes problemas no relacionados).
  • He agregado las dependencias atmosphere-runtime-native, atmosphere-compat-jbossweb y atmosphere-compat-tomcat.

Ninguno de estos ha cambiado el comportamiento del servicio. Y, de nuevo, parece funcionar bien cuando se ejecuta en Eclipse.

Medio ambiente: Ubuntu 14.04 LTS. Tomcat 7.0.54. Ambiente 2.1.5. Para un cliente, solo estoy usando telnet en este momento.

(Este código es un poco más complicado que las muestras porque tengo varias rutas diferentes que quiero admitir, y estoy usando el método propuesto por esta respuesta, que parece funcionar bien. También estoy devolviendo objetos de notificación en lugar de Strings. Esto también parece estar funcionando bien. He eliminado la mayor parte de la autenticación para mayor claridad.)

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>

de 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); } }

de ValidationsResource.java:

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

de 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); } }

============ Fin del mensaje original ======================

Actualizado el 15 de octubre de 2014:

Volví a este problema después de un tiempo en un proyecto diferente. Después de actualizar el proyecto con una nueva versión de Atmosphere (2.2.3), no encuentro diferencia en el comportamiento. Todavía es el caso que, al ejecutar el servicio en una computadora diferente a la que el cliente está ejecutando, las transmisiones de la atmósfera no son recibidas por el cliente hasta que se cierra Tomcat. Cuando se ejecuta el cliente y el servicio en la misma computadora, todo funciona como se espera.

Entonces, para determinar dónde se encuentra el problema, comencé simplemente a usar una de las aplicaciones de muestra de Atmosphere en mis pruebas. Estoy usando la aplicación de muestra jersey-pubsub (con actualizaciones menores para que compile), porque esa es la que está más cerca de lo que estoy tratando de hacer. Creé un nuevo entorno de servidor para ejecutar la aplicación de muestra, para minimizar cualquier variable basada en la configuración de Linux. Estos son los nuevos pasos: tal vez alguien pueda replicar el comportamiento.

Para obtener un nuevo servidor con Tomcat7 instalado (estoy usando Vagrant y VirtualBox para estas pruebas):

host$ vagrant init ubuntu/trusty64 host$ nano Vagrantfile

cambiar la configuración de red a una IP conocida: 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

Siguiendo estos pasos, terminé con Tomcat 7.0.52 y Ubuntu 14.04

Tengo una copia del proyecto jersey-pubsub (sin proyecto principal, etc.) que construyo usando

host$ mvn clean install

y luego implementar por

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

Puedo probar esto usando telnet, por ejemplo:

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

En este punto, telnet continúa esperando datos. En el registro del servidor Tomcat, puedo ver una entrada:

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

Luego envío una solicitud POST al servidor. Estoy usando POSTman para esto, pero no creo que importe.

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>

En el registro del servidor puedo ver que el servidor cree que transmite el mensaje:

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

pero nada aparece en el cliente de telnet. Puedo repetir ad infinitum y no ver ningún resultado, hasta que cierre Tomcat, momento en el que Telnet recibe todos los mensajes de difusión inmediatamente.

Por el contrario, si despliegue el servicio en una instancia de tomcat que se ejecute en el equipo host, o si ejecuto telnet dentro de la instancia vagabundo, todo funciona como se espera:

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

Si luego envío la misma solicitud POST, inmediatamente recibo el mensaje de difusión en telnet. El comportamiento parece ser que si el servicio y el cliente no están en la misma computadora, entonces el tráfico de la red se mantiene mientras Tomcat se está ejecutando.

Aquí está el código fuente de mi copia de la muestra jersey-pubsub, con los cambios suficientes para que compile y construya como un proyecto independiente.

EventsLogger.java: (Sin cambios excepto para eliminar @Override en 2 lugares para que Eclipse deje de quejarse)

FileResource.java: (Sin cambios)

JerseyPubSub.java: (Sin cambios)

web.xml: (Sin cambios)

pom.xml (modificado para compilar como independiente, sin referencia al padre 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>


Eche un vistazo a la tabla de referencia de dependencia rápida en la parte inferior de esta página

Asegúrese de tener los archivos jar correctos en su ruta de clase para la versión específica de tomcat que está utilizando.

Ver mi pom.xml aquí donde tengo una sección de perfil con un par de opciones de contenedor.

Intente ejecutar la mvn dependency:tree desde la línea de comando. Quizás el jersey de atmósfera está trayendo el tiempo de ejecución de la atmósfera como una dependencia transitiva. En ese caso, querrá excluirlo para tomcat 7.


Después de volver a este problema después de varios meses, pude descubrir por qué estaba viendo este comportamiento: era específicamente el cliente incorporado de Mac telnet que se comportaba mal. Confirmé que las respuestas se registraron de inmediato cuando usé telnet desde Windows o Linux, y también probé con un cliente Mac telnet diferente, y también se comportó como se esperaba. Aunque trabajé con él durante un tiempo, no pude averiguar si había opciones de telnet que pudiera especificar en la Mac que hicieran que se comportara de una manera comparable a las de Linux con las que estaba probando.