Skip to content

Ts.ED Integration

The @monque/tsed package provides a seamless integration between Monque and Ts.ED, allowing you to define jobs and cron jobs using decorators and leverage dependency injection.

Method / TypeDescription
MonqueModuleMain Ts.ED module
@JobController()Register a job controller
@Job()Register a job handler
@Cron()Register a scheduled job
MonqueServiceInjectable job management service
bun add @monque/tsed @monque/core mongodb

Monque requires several peer dependencies to be present in your project. While many modern package managers (like Bun or NPM 7+) install peer dependencies automatically, it is highly recommended to install them explicitly to ensure version consistency and avoid unexpected resolution issues.

PackageVersionRequired
@monque/core^1.1.0Yes
mongodb^7.0.0Yes
@tsed/core^8.24.0Yes
@tsed/di^8.24.0Yes
@tsed/mongoose^8.24.0Only for Mongoose integration

Import MonqueModule in your Server.ts and configure the connection via the @Configuration decorator. Monque supports multiple database resolution strategies to fit your application’s architecture.

Use this if you already have a connected native MongoDB Db instance available synchronously.

import { Configuration } from "@tsed/di";
import { MonqueModule } from "@monque/tsed";

@Configuration({
  imports: [MonqueModule],
  monque: {
    enabled: true,
    db: myExistingDbInstance,
  }
})
export class Server {}

The recommended approach if you need to establish a connection during application bootstrap. The factory supports async execution.

// src/Server.ts
import { Configuration } from "@tsed/di";
import { MonqueModule } from "@monque/tsed";
import "@tsed/platform-express";
import { MongoClient } from "mongodb";

@Configuration({
  imports: [MonqueModule],
  monque: {
    enabled: true,
    dbFactory: async () => {
        const client = await MongoClient.connect(process.env.MONGO_URL!);
        return client.db("my-app");
    },
    collectionName: "custom_jobs" // Optional: defaults to "monque_jobs"
  }
})
export class Server {}

If your application already uses @tsed/mongoose, Monque can reuse the existing connection. It automatically extracts the native Db instance from the Mongoose connection registry. Monque does not need its own connection string in this case; it simply hooks into the established Mongoose pool.

import { Configuration } from "@tsed/di";
import { MongooseModule, MongooseService } from "@tsed/mongoose";
import { MonqueModule } from "@monque/tsed";

@Configuration({
  imports: [
    MongooseModule, // Establish Mongoose connections
    MonqueModule    // Hooks into existing Mongoose connections
  ],
  mongoose: [{
    id: "default",
    url: "mongodb://localhost:27017/my-app" // Mongoose manages this connection
  }],
  monque: {
    enabled: true,
    dbToken: MongooseService,        // Reference the Mongoose service
    mongooseConnectionId: "default" // Identify which connection to reuse
  }
})
export class Server {}

Create a class decorated with @JobController. Related job handlers are grouped here, similar to how REST controllers group HTTP endpoints. Methods decorated with @Job will process jobs.

Monque is designed with type safety as a core principle. You can define job payloads using TypeScript interfaces and pass them as generics to the Job<T> type:

import { JobController, Job } from "@monque/tsed";
import type { Job as MonqueJob } from "@monque/core";

interface SendEmailPayload {
  to: string;
  subject: string;
  templateId: string;
}

@JobController("email") // Optional namespace prefix: "email."
export class EmailJobs {
  @Job("send", { concurrency: 5 }) // Full job name: "email.send"
  async sendEmail(job: MonqueJob<SendEmailPayload>) {
    // job.data is fully typed
    const { to, subject } = job.data;
    console.log(`Sending email to ${to}...`);
  }
}

Use the @Cron decorator to schedule recurring tasks. Cron jobs are automatically registered and scheduled with Monque during the application’s $onInit lifecycle phase.

import { JobController, Cron } from "@monque/tsed";

@JobController()
export class ReportJobs {
  @Cron("0 0 * * *", { name: "daily-report" })
  async generateDailyReport() {
    console.log("Generating report...");
  }
}

Inject MonqueService into any Ts.ED Service or Controller to dispatch jobs.

import { Service, Inject } from "@tsed/di";
import { MonqueService } from "@monque/tsed";

@Service()
export class AuthService {
  @Inject()
  private monque: MonqueService;

  async registerUser(user: { email: string }) {
    // Dispatch background job
    await this.monque.enqueue("email.send", {
      to: user.email,
      subject: "Welcome!"
    });
  }
}

One of the key benefits of the Ts.ED integration is Job Isolation. Every job execution runs in its own dedicated DIContext. This ensures that:

  • Request-scoped services (scoped to ProviderScope.REQUEST) are fresh for each job execution.
  • State does not leak between different job executions.
  • You can use standard Ts.ED patterns for context-bound logic (e.g. PlatformContext).

In production environments, you may want to separate your API servers (producers) from your worker servers (consumers). Use disableJobProcessing to create producer-only instances:

// API Server - Only enqueues jobs, doesn't process them
@Configuration({
  imports: [MonqueModule],
  monque: {
    dbFactory: async () => client.db("myapp"),
    disableJobProcessing: true  // Producer-only mode
  }
})
export class ApiServer {}

// Worker Server - Processes jobs
@Configuration({
  imports: [MonqueModule],
  monque: {
    dbFactory: async () => client.db("myapp"),
    // disableJobProcessing defaults to false
  }
})
export class WorkerServer {}

This pattern enables horizontal scaling where API nodes focus on handling requests while dedicated worker nodes process background jobs.

An injectable wrapper for the main Monque instance. It provides a DI-friendly way to manage jobs, delegating all calls to the underlying Monque engine.

Commonly used methods:

Use @tsed/platform-http/testing and PlatformTest to test your jobs. You can mock MonqueService or use a real MongoDB connection with Testcontainers.

import { PlatformTest } from "@tsed/platform-http/testing";
import { MonqueService } from "@monque/tsed";

describe("EmailJobs", () => {
  beforeEach(PlatformTest.create);
  afterEach(PlatformTest.reset);

  it("should process email", async () => {
      const service = PlatformTest.get(MonqueService);
      // ... test logic ...
  });
});