Hello,
I have a monorepo project with multiple NestJS apps, and I’m using nestjs-temporal-core
. I have two services:
-
API Service
-
Worker Service
I created a shared activity, SummarizationService
, that I would like to use in both the API and Worker services.
Summarization Module
import { Module } from '@nestjs/common';
import { LlmModule } from '@corolair/libs/services/shared/llm/llm.module';
import { LLMMonitoring } from '@corolair/libs/services/shared/llm/monitoring/monitoring.module';
import { SummarizationService } from './summarization.service';
@Module({
imports: [LlmModule, LLMMonitoring],
providers: [SummarizationService],
exports: [SummarizationService],
})
export class SummarizationModule {}
Summarization Service
import { Injectable } from '@nestjs/common';
@Injectable()
export class SummarizationService {
constructor(
private readonly azureFoundryService: AzureFoundryService,
private readonly contextService: ContextService,
private readonly langfuseService: LangfuseService
) {}
async createSummary(transcript: string) {
// implementation...
}
}
- Injecting this service into my API service works fine.
Worker Module
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TemporalModule } from 'nestjs-temporal-core';
import path from 'path';
import { WorkerTaskQueue } from '@corolair/libs/shared/enums';
import { SummarizationModule } from '@corolair/libs/services/shared/summarization/summarization.module';
import { DocumentWorkerService } from './document-worker.service';
import { NodeWorkerService } from './node-worker.service';
@Module({
imports: [
ConfigModule,
SummarizationModule,
TemporalModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
connection: {
address: configService.get('TEMPORAL_ADDRESS', 'localhost:7233'),
namespace: configService.get('TEMPORAL_NAMESPACE', 'default'),
},
enableLogger: true,
logLevel: 'info',
taskQueue: WorkerTaskQueue.NODE_WORKER,
worker: {
activityClasses: [DocumentWorkerService],
autoStart: true,
workflowsPath: path.resolve(
__dirname,
'../../../libs/services/shared/workflows/src/index.ts'
),
},
}),
}),
],
providers: [NodeWorkerService, DocumentWorkerService],
})
export class NodeWorkerModule {}
Worker Activity
import { Injectable } from '@nestjs/common';
import { Activity, ActivityMethod } from 'nestjs-temporal-core';
import { SummarizationService } from '@corolair/libs/services/shared/summarization/summarization.service';
@Injectable()
@Activity()
export class DocumentWorkerService {
constructor(private readonly summarizationService: SummarizationService) {
console.log('SummarizationService injected?', !!summarizationService);
}
@ActivityMethod()
async summarizeDocument(documentId: string): Promise<string> {
console.log('summarizeDocument', documentId);
return this.summarizationService.createSummary("...long text...");
}
}
Issue
When I run the workflow, I get the following error:
cause: [ActivityFailure: Activity task failed] {
cause: TypeError: Cannot read properties of undefined (reading 'createSummary')
}
This indicates that summarizationService
is undefined
in the worker activity.
What I think is happening
-
In
nestjs-temporal-core
, when you useactivityClasses: [DocumentWorkerService]
, the library instantiates the class itself, bypassing NestJS DI. -
As a result, the
SummarizationService
constructor injection does not work, and the activity cannot access it.
I’d like guidance on the best way to use a NestJS service inside a Temporal worker activity so that:
-
The worker can run automatically.
-
The activity has access to the Nest-managed
SummarizationService
.