Demo

@Bean

Mark a method on a @Service as a factory that provides a singleton into the DI container. Use it to register third-party libraries (BullMQ Queue, Redis clients, SDK clients) that are not decorated with @Service.

What it does

  • Decorate a private (or public) method on a @Service class
  • The method’s return value is registered as a singleton in the plugin DI container
  • Other services/controllers can then @Inject that instance by type (or the returned class)
  • Ideal for wrapping libraries you do not own (BullMQ, ioredis, AWS SDK, etc.)

Rules

  • Host class must be @Service() and listed in the module providers
  • Factory runs during DI setup — keep it side-effect light (create client / queue; defer heavy work)
  • Return one concrete instance per @Bean method
  • Constructor injection is not supported anywhere — consumers inject with property @Inject

BullMQ Queue example

Common pattern: expose a Queue for custom background work. For recurring schedules prefer CronJobService instead.

TSXfactory
1import { Queue } from "bullmq"; 2import { Bean, Service } from "@quan-erp/shared-backend-core"; 3 4@Service() 5export class QueueRegistryService { 6 @Bean() 7 private registerQueue() { 8 return new Queue("my-queue", { connection: redisOptions }); 9 } 10}
TSXinject consumer
1import { Queue } from "bullmq"; 2import { Inject, Service } from "@quan-erp/shared-backend-core"; 3 4@Service() 5export class JobPublisherService { 6 @Inject(Queue) // or the concrete token your factory returns 7 private queue: Queue; 8 9 async enqueue(payload: unknown) { 10 await this.queue.add("task", payload); 11 } 12}

When to use

  • Yes — Queue / Worker / Redis / HTTP SDK clients that need a single shared instance
  • Yes — adapters that need env/config at construction time
  • No — normal plugin services (use @Service + @Inject)
  • No — cron schedules (use CronJobService; see Cron job)

Practices

  • Keep factory methods small and named clearly (registerX / createX)
  • Read connection options from PluginEnv / base env — never hardcode secrets
  • On uninstall, disconnect clients in @OnUninstall if the library needs cleanup
  • Register the host @Service in @Module({ providers }) so the factory actually runs