Nest.js + DBOS
This guide shows you how to add the open source DBOS Transact library to your existing Nest.js application to durably execute it and make it resilient to any failure.
Installation and Requirements
Install DBOS TypeScript with npm install @dbos-inc/dbos-sdk
and add a dbos-config.yaml
file to the root of your project:
language: node
telemetry:
logs:
logLevel: 'info'
Bootstrapping DBOS
This example was bootstrapped with nest new nest-starter
and configured to use NPM.
Modify your bootstrap function to import and launch DBOS:
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { DBOS } from "@dbos-inc/dbos-sdk";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await DBOS.launch();
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
Register Services With DBOS
To integrate a Nest.js service with DBOS, your service class must extend the DBOS ConfiguredInstance class. By extending ConfiguredInstance
, you add your class instance methods to DBOS Transact's internal registry. During workflow recovery, this registry enables DBOS to recover workflows using the right class instance.
Here is an example of a Nest.js service implementing a simple two-step workflow:
// app.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from 'nestjs-prisma';
import { ConfiguredInstance, DBOS, InitContext } from '@dbos-inc/dbos-sdk';
@Injectable()
export class AppService extends ConfiguredInstance {
constructor(
name: string, // You must provide a name to uniquely identify this class instance in DBOS's internal registry.
private readonly prisma: PrismaService, // An example service dependency
) {
super(name);
}
// Optionally perform some asynchronous setup work
async initialize(): Promise<void> {}
@DBOS.workflow()
async businessLogic() {
await this.step1();
await this.step2();
}
@DBOS.step()
async step1() {
...
}
@DBOS.step()
async step2() {
...
};
}
Add Nest.js Providers
We also need to write the code that Nest will use to instantiate this service during dependency injection. We'll do this with a custom Factory Provider. Here is an example:
// app.modules.ts
import { Module } from '@nestjs/common';
import { Provider } from '@nestjs/common/interfaces';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PrismaService, PrismaModule } from 'nestjs-prisma';
import { DBOS } from '@dbos-inc/dbos-sdk';
export const dbosProvider: Provider = {
provide: AppService,
useFactory: (prisma: PrismaService) => {
return new AppService("dbosService", prisma);
},
inject: [PrismaService],
};
@Module({
imports: [PrismaModule.forRoot()],
controllers: [AppController],
providers: [dbosProvider],
})
export class AppModule {}
If you need multiple instances of your DBOS class, you must give them distinct names (dbosService
in this case). You can create a dedicated provider for each or use a single provider for multiple classes, at your convenience.