Event-Driven & CQRS

Preview — 3 of 10 questions

You need fan-out to multiple independent subscribers AND load-balanced processing within each subscriber type. What is the correct Kafka design, and how does it differ from naive @EventPattern use?

javascript
// inventory-service: its own group
consumer: { groupId: 'inventory' }
// analytics-service: a different group -> also gets every message
consumer: { groupId: 'analytics' }
// scale inventory to 3 instances -> all share groupId 'inventory' (partitions split)
AOne consumer group shared by every service — gives both behaviours
BEach logical subscriber type gets its own groupId (fan-out across groups); multiple instances of that type share the group (load-balance within the group)
CUnique groupId per instance for everything
DAvoid groups entirely and broadcast manually

In @nestjs/cqrs, what are the distinct responsibilities of CommandBus, QueryBus, and EventBus?

javascript
import { CommandBus, QueryBus, EventBus } from '@nestjs/cqrs';

await this.commandBus.execute(new PublishArticleCommand(id)); // 1 handler
const dto = await this.queryBus.execute(new GetArticleQuery(id)); // 1 handler
this.eventBus.publish(new ArticlePublishedEvent(id)); // 0..n handlers + sagas
AThey are interchangeable wrappers over the same dispatcher
BEventBus returns a value to the publisher; commands don't
CCommandBus dispatches state-changing commands to a single handler; QueryBus dispatches reads to a single handler; EventBus publishes facts to zero-or-many event handlers/sagas
DQueryBus mutates state, CommandBus reads

A @Saga() in @nestjs/cqrs listens to the event stream. Which RxJS operator selects the events it should react to, and what must the saga return?

javascript
import { Saga, ICommand, ofType } from '@nestjs/cqrs';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Saga()
articlePublished = (events$: Observable<any>): Observable<ICommand> =>
  events$.pipe(
    ofType(ArticlePublishedEvent),
    map((e) => new NotifySubscribersCommand(e.articleId)),
  );
AofType(SomeEvent); the saga returns an Observable<ICommand> so each matched event maps to a command dispatched automatically
Bfilter(); it must return void
Cmap(); it must return a Promise
DmergeAll(); it returns the raw event

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.