添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm creating few microservices using nestjs .

For instance I have x , y & z services all interconnected by grpc but I want service x to send updates to a webapp on a particular entity change so I have considered server-sent-events [open to any other better solution] .

Following the nestjs documentation , they have a function running at n interval for sse route, seems to be resource exhaustive. Is there a way to actually sent events when there's a update.

Lets say I have another api call in the same service that is triggered by a button click on another webapp, how do I trigger the event to fire only when the button is clicked and not continuously keep sending events. Also if you know any idiomatic way to achieve this which getting hacky would be appreciated, want it to be last resort.

[BONUS Question]

I also considered MQTT to send events. But I get a feeling that it isn't possible for a single service to have MQTT and gRPC . I'm skeptical of using MQTT because of its latency and how it will affect internal message passing . If I could limit to external clients it would be great (i.e, x service to use gRPC for internal connections and MQTT for webapp just need one route to be exposed by mqtt). (PS I'm new to microservices so please be comprehensive about your solutions :p)

Thanks in advance for reading till end!

You can. The important thing is that in NestJS SSE is implemented with Observables, so as long as you have an observable you can add to, you can use it to send back SSE events. The easiest way to work with this is with Subject s . I used to have an example of this somewhere, but generally, it would look something like this

@Controller()
export class SseController {
  constructor(private readonly sseService: SseService) {}
  @SSE()
  doTheSse() {
    return this.sseService.sendEvents();
@Injectable()
export class SseService {
  private events = new Subject();
  addEvent(event) {
    this.events.next(event);
  sendEvents() {
    return this.events.asObservable();
@Injectable()
export class ButtonTriggeredService {
  constructor(private readonly sseService: SseService) {}
  buttonClickedOrSomething() {
    this.sseService.addEvent(buttonClickedEvent);

Pardon the pseudo-code nature of the above, but in general it does show how you can use Subjects to create observables for SSE events. So long as the @SSE() endpoint returns an observable with the proper shape, you're golden.

is there any way to isolate that event subject to a particular user? For SSE in controller I'm doing something like @Sse('/status/update/:userId'). Thinking I should use a map<userId, subject>. Any better solutions? – Nikhil.Nixel Apr 21, 2021 at 20:02 The map doesn't sound like a terrible idea to me. I don't know much else about sse filtering, so it might be something to look into – Jay McDoniel Apr 21, 2021 at 20:06 @Nikhil.Nixel have you found any solution to isolate for a particular user? Currently in the same situation as you are – Mohaimin Oct 23, 2021 at 10:44 I did something like this, @Sse('/status/update/:userId') then I could store subjects in map with key as userId, if you have large number of users its not ideal for the RAM since it will keep hogging those spaces if you have too many subjects because of too many users – Nikhil.Nixel Oct 23, 2021 at 14:05

There is a better way to handle events with SSE of NestJS:

Please see this repo with code example:

https://github.com/ningacoding/nest-sse-bug/tree/main/src

Where basically you have a service:

import {Injectable} from '@nestjs/common';
import {fromEvent} from "rxjs";
import {EventEmitter} from "events";
@Injectable()
export class EventsService {
    private readonly emitter = new EventEmitter();
    subscribe(channel: string) {
        return fromEvent(this.emitter, channel);
    emit(channel: string, data?: object) {
        this.emitter.emit(channel, {data});

Obviously, channel can be any string, as recommendation use path style.

For example: "events/for/<user_id>" and users subscribed to that channel will receive only the events for that channel and only when are fired ;) -

Fully compatible with @UseGuards, etc. :)

Additional note: Don't inject any service inside EventsService, because of a known bug.

@BennisonJ Please see the repo with code example: github.com/ningacoding/nest-sse-bug/tree/main/src – NingaCodingTRV Mar 2 at 1:21

Yes, this is possible, instead of using interval, we can use event emitter. Whenever the event is emitted, we can send back the response to the client.

notification.controller.ts

import { Public } from 'src/decorators';
import { Observable } from 'rxjs';
import { FastifyReply } from 'fastify';
import { NotificationService } from './notification.service';
import { Sse, Controller, Res } from '@nestjs/common';
@Public()
@Controller()
export class NotificationController {
  constructor(private notificationService: NotificationService) {}
  @Sse('notifications')
  async sendNotification(@Res() reply: FastifyReply): Promise<Observable<any>> {
    return await this.notificationService.handleConnection();

notification.service.ts

import { Injectable } from '@nestjs/common';
import { Subject } from 'rxjs';
@Injectable()
export class NotificationService {
  notificationEvent: Subject<any> = new Subject();
  async handleConnection() {
    setInterval(() => {
      this.notificationEvent.next({ data: { message: 'Hello World' } });
    }, 1000);
    return this.notificationEvent.asObservable();
  • here I used the setInterval, just to emit a new event. You can emit the new event in your code wherever you want without the setInterval method.
  • I found some problem with this approach, and I shared the link below, check the below link as well. sse in nestJs
  • return new Observable((subscriber) => { while(arr.len){ subscriber.next(arr.pop()); // data have to return in every chunk if(arr.len == 0) subscriber.complete(); // complete the subscription Answers should include an explanation of why a code snippet is a solution, please edit this answer to add some context – hardillb May 13, 2022 at 10:00

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.