2015-03-22 15 views
6

Sul lato client JavaScript HoStomp oltre websocket utilizzando primavera e sockJS messaggio perso

stomp.subscribe("/topic/path", function (message) { 
     console.info("message received"); 
    }); 

E sul lato server

public class Controller { 
    private final MessageSendingOperations<String> messagingTemplate; 
    @Autowired 
    public Controller(MessageSendingOperations<String> messagingTemplate) { 
     this.messagingTemplate = messagingTemplate; 
    } 
    @SubscribeMapping("/topic/path") 
    public void subscribe() { 
    LOGGER.info("before send"); 
    messagingTemplate.convertAndSend(/topic/path, "msg"); 
    } 
} 

Da questa configurazione, sono di tanto in tanto (circa una volta ogni 30 pagina si rinnova) sperimentando la caduta del messaggio, il che significa che non riesco a vedere né il messaggio "messaggio ricevuto" sul lato client né il traffico websocket dallo strumento di debug di Chrome.

"before send" è sempre registrato sul lato server.

Sembra che MessageSendingOperations non sia pronto quando lo chiamo nel metodo subscribe(). (se inserisco Thread.sleep (50), prima di chiamare messagingTemplate.convertAndSend il problema scomparirebbe (o molto meno probabilmente sarà riprodotto))

Mi chiedo se qualcuno abbia mai sperimentato lo stesso prima e se c'è un evento che può dimmi che MessageSendingOperations è pronto o no.

+0

è stomp.subscribe eseguito dopo che il dom è pronto? –

+0

@ ᴳᵁᴵᴰᴼ Sì. giusto. Posso vedere che il messaggio di iscrizione è stato inviato dal debug di Chrome per il traffico di rete websocket. Quindi non penso che sia il problema del lato client. – user2001850

risposta

4

Il problema che state affrontando è nella natura di clientInboundChannel che è ExecutorSubscribableChannel per impostazione predefinita.

Ha 3 subscribers:

0 = {[email protected]} "SimpleBroker[DefaultSubscriptionRegistry[cache[0 destination(s)], registry[0 sessions]]]" 
1 = {[email protected]} "UserDestinationMessageHandler[DefaultUserDestinationResolver[prefix=/user/]]" 
2 = {[email protected]} "SimpAnnotationMethodMessageHandler[prefixes=[/app/]]" 

che sono richiamato all'interno taskExecutor, quindi in modo asincrono.

La prima qui (SimpleBrokerMessageHandler (o StompBrokerRelayMessageHandler) se si utilizza broker-relay) è responsabile per registrare subscription per il topic.

L'operazione messagingTemplate.convertAndSend(/topic/path, "msg") può essere eseguita prima della registrazione della sottoscrizione per quella sessione WebSocket, poiché vengono eseguite nei thread separati. Quindi il gestore Broker non sa che tu invii il messaggio alla sessione.

Il @SubscribeMapping può essere configurato sul metodo con return, in cui il risultato di questo metodo verrà inviato come risposta a tale funzione subscription sul client.

HTH

+0

all'interno del mio metodo subscribe, stavo chiamando asincronicamente il livello di servizio come subscriableService.registerAndHandleWith (new Handler() {}). In modo che non posso tornare immediatamente in questo metodo. Cosa consiglieresti in questo scenario? Grazie. – user2001850

+0

'Future.get()' o 'CountDownLatch' da quel' registerAndHandleWith'. Dall'altro lato è possibile accedere a 'SimpleBrokerMessageHandler' e popolare alcuni impl personalizzati di' DefaultSubscriptionRegistry' per sovrascrivere 'addSubscriptionInternal' per aumentare alcuni' ApplicationEvent' personalizzati per ascoltarlo da qualche altro componente per inviare quel messaggio all'argomento, quando 'subscription' ci sarà già. È per caso, quando hai davvero bisogno di cose asincrone e non sovraccarichi l'esecutore di 'clientInboundChannel' per aspettare quel' Futuro'. –

+1

Grazie ancora Artem, presumo di non poter utilizzare l'SessionSubscribeEvent esistente in quanto mi dice solo che il client ha richiesto ma non significa che la registrazione dell'abbonamento sia stata completata (sarebbe bello avere qualcosa come SessionSubscribe ** d * *Evento). – user2001850

0

Un po 'tardi, ma ho pensato di aggiungere la mia soluzione. Stavo avendo lo stesso problema con la sottoscrizione non essere registrato prima che stavo inviando i dati attraverso il modello di messaggistica. Questo problema si è verificato raramente e imprevedibile a causa della corsa con lo DefaultSubscriptionRegistry.

Purtroppo, non ho potuto utilizzare il metodo di ritorno dello @SubscriptionMapping perché stavamo usando un mappatore di oggetti personalizzato modificato dinamicamente in base al tipo di utente (essenzialmente il filtro degli attributi).

Ho cercato attraverso il codice Spring e trovato SubscriptionMethodReturnValueHandler era responsabile dell'invio del valore restituito dei mapping di sottoscrizione e disponeva di un diverso messagingTemplate rispetto al del controller asincrono automaticamente !!

Quindi la soluzione stava automatizzando MessageChannel clientOutboundChannel nel mio controller asincrono e usando quello per creare un SimpMessagingTemplate.(Non puoi collegarlo direttamente perché avrai solo il modello che va al broker).

In metodi di sottoscrizione, ho quindi utilizzato il modello diretto mentre in altri metodi ho utilizzato il modello che è andato al broker.