Search code examples
javaandroidangularrabbitmqamqp

Queues are deleted after 6 minutes, when Android tablet goes in standby


After about 6 minutes the client (akà browser) doesn't receive any new updates from the subscribed queue, when the device is in sleep mode. If I look into RabbitMQ Management the related queues disappeared (named e.g. stomp-subscription-MBSsZ9XB0XCScXbSc3bCcg). After waking up of the device new queues are created and the messaging works only for new created messages. The old ones never reached the device.

Here is my setup:

  • Backend: Java application with Spring and RabbitTemplate
  • Frontend: Angular application, which subcribes via RxStompService
  • Use case: WebView running in a Xamarin.Forms app on an Android tablet, which opens the URL to the frontend application

This is how the message is sent from backend to frontend:

AMQPMessage<CustomNotificationMessage> msg = new AMQPMessage<CustomNotificationMessage>(
    1, SOME_ROUTING_KEY, mand, trigger, new CustomNotificationMessage() );
rabbitTemplate.setRoutingKey(SOME_ROUTING_KEY);
rabbitTemplate.convertAndSend(msg);

RabbitMqConfig.java:

@Bean
public RabbitTemplate rabbitTemplate() {
    CachingConnectionFactory connectionFactoryFrontend = new CachingConnectionFactory("some.url.com");
    connectionFactoryFrontend.setUsername("usr");
    connectionFactoryFrontend.setPassword("pass");
    connectionFactoryFrontend.setVirtualHost("frontend");

    RabbitTemplate template = new RabbitTemplate(connectionFactoryFrontend);      
    template.setMessageConverter(jsonMessageConverter());
    template.setChannelTransacted(true);
    template.setExchange("client-notification");
    return template;
}

My idea now is to use a TTL for the frontend queues. But how do I do that, where I don't have created a queue at all?

On the other side I see methods like setReceiveTimeout(), setReplyTimeout() or setDefaultReceiveQueue() in the RabbitTemplate, but I don't know if this would be right. Is it more a client thing? The Subscription on the client side looks like the following:

this.someSubscription = this.rxStompService.watch('/exchange/client-notification/SOME_ROUTING_KEY')
    .subscribe(async (message: Message) => {
    // do something with message
}

This is the according my-stomp-config.ts:

export const MyStompConfig: InjectableRxStompConfig = {
  // Which server?
  brokerURL: `${environment.BrokerURL}`,

  // Headers
  // Typical keys: login, passcode, host
  connectHeaders: {
    login: 'usr',
    passcode: 'pass',
    host: 'frontend'
  },

  // How often to heartbeat?
  // Interval in milliseconds, set to 0 to disable
  heartbeatIncoming: 0, // Typical value 0 - disabled
  heartbeatOutgoing: 20000, // Typical value 20000 - every 20 seconds

  // Wait in milliseconds before attempting auto reconnect
  // Set to 0 to disable
  // Typical value 500 (500 milli seconds)
  reconnectDelay: 500,

  // Will log diagnostics on console
  // It can be quite verbose, not recommended in production
  // Skip this key to stop logging to console
  debug: (msg: string): void => {
    //console.log(new Date(), msg);
  }
};

In the documentation I see a connectionTimeout parameter, but the default value should be ok.

Default 0, which implies wait for ever.

Some words about power management: I excluded the app from energy saving, but that doesn't change something. It also happens with the default browser.

How can I make the frontend queues live longer than six minutes?


Solution

  • The main problem is that you can't do anything if the operating system is cutting the ressources (WiFi, CPU, ...). If you awake the devices the queues are getting created again, but all old messages (when the device was sleeping) are lost.

    So the workaround is to reload the data if the device is wakeup. Because this is application specific code samples are not so useful. I use Xamarin.Forms OnResume() and MessagingCenter where I subscribe within my browser control. From there I execute a Javascript code with postMessage() and a custom message.

    The web application itself has a listener for these messages and reloads the data accordingly.