Brota SseEmitter.complete () desencadenar una reconexión EventSource - ¿Cómo cerrar la conexión del lado del servidor

xdhmoore:

Estoy tratando de establecer un SseEmitter primavera para enviar una secuencia de cambios del estado de un trabajo en ejecución. Parece estar funcionando, pero:

Siempre que llamo emitter.complete()en mi código de servidor Java, el Javascript EventSourcecliente llama a la registrada onerrorfunción y luego llama a mi Java punto final de nuevo con una nueva conexión. Esto sucede tanto en Firefox y Chrome.

Es probable que pueda enviar un mensaje explícito "de fin de datos" de Java y luego detectar que la llamada y eventSource.close()en el cliente, pero hay una manera mejor?

¿Cuál es el propósito de emitter.complete()que en ese caso?

Además, si siempre tengo que terminar la conexión en el cliente final, entonces creo que todas las conexiones en el lado del servidor se dará por terminado por cualquiera de un tiempo de espera o un error de escritura, en cuyo caso probablemente quiero enviar manualmente de nuevo un latido del corazón de algunas clase cada pocos segundos?

Se siente como que estoy perdiendo algo si estoy teniendo que hacer todo esto.

Ashraf Sarhan:

He añadido lo siguiente a mi solicitud de inicio de primavera para activar la conexión SSE close()

Lado del servidor:

  1. Crear un simple controlador que devuelve SseEmitter.
  2. Envolver la lógica backend en un único servicio ejecutor hilo.
  3. Envíe sus eventos a la SseEmitter.
  4. Enviar completa en un evento de tipo completo a través de la SseEmitter.

    @RestController
    public class SearchController {
    
    @Autowired
    private SearchDelegate searchDelegate;
    
    @GetMapping(value = "/{customerId}/search")
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "Search Sources", notes = "Search Sources")
    @ApiResponses(value = {
            @ApiResponse(code = 201, message = "OK"),
            @ApiResponse(code = 401, message = "Unauthorized")
    })
    @ResponseBody
    public SseEmitter search(@ApiParam(name = "searchCriteria", value = "searchCriteria", required = true) @ModelAttribute @Valid final SearchCriteriaDto searchCriteriaDto) throws Exception {
        return searchDelegate.route(searchCriteriaDto);
      }
    }
    
    
    
    @Service
    public class SearchDelegate {
    public static final String SEARCH_EVENT_NAME = "SEARCH";
    public static final String COMPLETE_EVENT_NAME = "COMPLETE";
    public static final String COMPLETE_EVENT_DATA = "{\"name\": \"COMPLETED_STREAM\"}";
    
    @Autowired
    private SearchService searchService;
    
    private ExecutorService executor = Executors.newCachedThreadPool();
    
    public SseEmitter route(SearchCriteriaDto searchCriteriaDto) throws Exception {
        SseEmitter emitter = new SseEmitter();
        executor.execute(() -> {
            try {
                if(!searchCriteriaDto.getCustomerSources().isEmpty()) {
                    searchCriteriaDto.getCustomerSources().forEach(customerSource -> {
                        try {
                            SearchResponse searchResponse = searchService.search(searchCriteriaDto);
                            emitter.send(SseEmitter.event()
                                    .id(customerSource.getSourceId())
                                    .name(SEARCH_EVENT_NAME)
                                    .data(searchResponse));
                        } catch (Exception e) {
                            log.error("Error while executing query for customer {} with source {}, Caused by {}",
                                    customerId, source.getType(), e.getMessage());
                        }
                    });
                }else {
                    log.debug("No available customerSources for the specified customer");
                }
                emitter.send(SseEmitter.event().
                        id(String.valueOf(System.currentTimeMillis()))
                        .name(COMPLETE_EVENT_NAME)
                        .data(COMPLETE_EVENT_DATA));
                emitter.complete();
            } catch (Exception ex) {
                emitter.completeWithError(ex);
            }
        });
        return emitter;
       }
    }
    

Lado del cliente:

  1. Puesto que especificamos la namedel caso en nuestra SseEmitter, un evento serán enviados en el navegador a la escucha para el nombre del evento especificado; el código fuente del sitio web debe utilizar addEventListener()para detectar los eventos mencionados. ( Nota: El onmessagegestor se llama si no se especifica el nombre del evento para un mensaje )
  2. Llame a la EventSourcedel COMPLETEcaso para liberar la conexión del cliente.

https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events

var sse = new EventSource('http://localhost:8080/federation/api/customers/5d96348feb061d13f46aa6ce/search?nativeQuery=true&queryString=*&size=10&customerSources=1,2,3&start=0');

sse.addEventListener("SEARCH", function(evt) {
   var data = JSON.parse(evt.data);
   console.log(data);
});

sse.addEventListener("COMPLETE", function(evt) {
   console.log(evt);
   sse.close();
});

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=219590&siteId=1
Recomendado
Clasificación