Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update NestJS sample #393

Merged
merged 3 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ jobs:
nestjs-exchange-rates,
timer-examples
]
exclude:
- node: 16
project: nestjs-exchange-rates

steps:
- uses: actions/checkout@v4
Expand Down
1 change: 1 addition & 0 deletions nestjs-exchange-rates/.env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NODE_ENV=<dev|production>
4 changes: 4 additions & 0 deletions nestjs-exchange-rates/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/dist
/node_modules
.env

# Created by .ignore support plugin (hsz.mobi)
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
Expand Down
27 changes: 23 additions & 4 deletions nestjs-exchange-rates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,31 @@ This sample app is based on this [blog post about caching API requests with long
## Installation

```bash
$ npm install
npm install
```

Create an `.env` file from the `.env.template` and chose `dev` or `production`.

- `dev` must be used for testing purposes only
- `production` must be used for production in order to have compiled workflows

Note: you can't start your worker with `npm run start:worker` in production mode.

## Running the app

1. `temporal server start-dev` to start [Temporal Server](https://github.com/temporalio/cli/#installation).
1. `npm run worker` to start the Worker.
1. `npm run start` to start the NestJS server.
1. Visit `http://localhost:3000/exchange-rates/AUD` to see the most recent exchange rate for AUD (Australian Dollar)
2. `npm run start:worker` to start the Worker.
3. `npm run start:server` to start the NestJS server.
4. Visit `http://localhost:3000/exchange-rates/AUD` to see the most recent exchange rate for AUD (Australian Dollar)

## Building the app

For production optimized builds, webpack is used to squash the files into a big `main.js` under the folders `dist/apps/server/` and `dist/apps/worker/`

1. `npm run build:server:prod`
2. `npm run build:worker:prod`

You can locally test your builds before deploying to another server or to the cloud with:

1. `npm run start:server:prod`
2. `npm run start:worker:prod`
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { Client, WorkflowExecutionAlreadyStartedError, Connection, ConnectionOptions } from '@temporalio/client';
import { Provider } from '@nestjs/common';
import {
Client,
WorkflowExecutionAlreadyStartedError,
Connection,
ConnectionOptions,
Workflow,
WorkflowHandle,
} from '@temporalio/client';
import { taskQueue } from '@app/shared';

export const exchangeRatesProviders = [
export const exchangeRatesProviders: Provider[] = [
{
provide: 'CONNECTION_CONFIG',
useValue: {
Expand All @@ -26,7 +34,7 @@ export const exchangeRatesProviders = [
{
provide: 'EXCHANGE_RATES_WORKFLOW_HANDLE',
useFactory: async (client: Client) => {
let handle;
let handle: WorkflowHandle<Workflow>;
try {
handle = await client.workflow.start('exchangeRatesWorkflow', {
taskQueue,
Expand All @@ -36,7 +44,7 @@ export const exchangeRatesProviders = [
} catch (err) {
if (err instanceof WorkflowExecutionAlreadyStartedError) {
console.log('Reusing existing exchange rates workflow');
handle = await client.workflow.getHandle('exchange-rates');
handle = client.workflow.getHandle('exchange-rates');
} else {
throw err;
}
Expand Down
21 changes: 21 additions & 0 deletions nestjs-exchange-rates/apps/worker/scripts/build-workflow-bundle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { bundleWorkflowCode } from '@temporalio/worker';
import { readFile, writeFile } from 'fs/promises';
import * as path from 'path';

async function bundle() {
const { code } = await bundleWorkflowCode({
workflowsPath: require.resolve('../src/temporal/workflows'),
});
const tsconfigPath = path.join(__dirname, '../tsconfig.app.json');
const tsconfigData = await readFile(tsconfigPath, 'utf-8');
const tsconfig = JSON.parse(tsconfigData);
const codePath = path.join(__dirname, `../${tsconfig.compilerOptions.outDir}/workflow-bundle.js`);

await writeFile(codePath, code);
console.log(`Bundle written to ${codePath}`);
}

bundle().catch((err) => {
console.error(err);
process.exit(0);
});
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { ActivitiesModule } from '../activities/activities.module';
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { ActivitiesModule } from '../activities/activities.module';
import { exchangeRatesWorkerProviders } from './exchange-rates-worker.providers';
import { ExchangeRatesWorkerService } from './exchange-rates-worker.service';

@Module({
imports: [ActivitiesModule],
imports: [
ConfigModule.forRoot({
envFilePath: '.env',
isGlobal: true,
}),
ActivitiesModule,
],
controllers: [],
providers: [...exchangeRatesWorkerProviders, ExchangeRatesWorkerService],
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
import { ConfigService } from '@nestjs/config';
import { ActivitiesService } from '../activities/activities.service';
import { Worker } from '@temporalio/worker';
import { taskQueue } from '@app/shared';

export const exchangeRatesWorkerProviders = [
{
provide: 'EXCHANGE_RATES_WORKER',
inject: [ActivitiesService],
useFactory: async (activitiesService: ActivitiesService) => {
inject: [ActivitiesService, ConfigService],
useFactory: async (activitiesService: ActivitiesService, configService: ConfigService) => {
const activities = {
getExchangeRates: activitiesService.getExchangeRates.bind(activitiesService),
};

const workflowOption =
configService.get<string>('NODE_ENV') === 'production'
? {
workflowBundle: {
codePath: `${__dirname}/workflow-bundle.js`,
},
}
: { workflowsPath: require.resolve('../temporal/workflows') };

const worker = await Worker.create({
workflowsPath: require.resolve('../temporal/workflows'),
taskQueue,
...workflowOption,
activities,
});

Expand Down
3 changes: 2 additions & 1 deletion nestjs-exchange-rates/nest-cli.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"monorepo": true,
"root": "apps/server",
"compilerOptions": {
"deleteOutDir": true,
"webpack": false,
"tsConfigPath": "apps/server/tsconfig.app.json"
},
Expand Down Expand Up @@ -37,4 +38,4 @@
}
}
}
}
}
87 changes: 46 additions & 41 deletions nestjs-exchange-rates/package.json
Original file line number Diff line number Diff line change
@@ -1,59 +1,64 @@
{
"name": "nest-typescript-starter",
"name": "nestjs-typescript-starter",
"private": true,
"version": "1.0.0",
"description": "Nest TypeScript starter repository",
"version": "2.0.0",
"description": "NestJS TypeScript starter repository",
"license": "MIT",
"scripts": {
"prebuild": "rimraf dist",
"build": "nest build",
"build": "npm run build:server && npm run build:worker",
"build:server": "nest build --webpack server",
"build:worker": "nest build --webpack worker && ts-node apps/worker/scripts/build-workflow-bundle.ts",
"format": "prettier --write \"apps/**/*.ts\" \"libs/**/*.ts\"",
"start": "nest start server",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"start:server": "nest start server",
"start:server:dev": "nest start --watch",
"start:server:debug": "nest start --debug --watch",
"start:server:prod": "node dist/apps/server/main",
"start:worker": "nest start worker",
"start:worker:dev": "nest start worker --watch",
"start:worker:debug": "nest start worker --debug --watch",
"start:worker:prod": "node dist/apps/worker/main",
"test": "jest",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"worker": "nest start worker"
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix"
},
"dependencies": {
"@nestjs/axios": "0.1.0",
"@nestjs/common": "^8.4.7",
"@nestjs/core": "^8.4.7",
"@nestjs/platform-express": "^8.4.7",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"@nestjs/axios": "3.1.2",
"@nestjs/common": "^10.4.8",
"@nestjs/config": "^3.3.0",
"@nestjs/core": "^10.4.8",
"@nestjs/platform-express": "^10.4.8",
"axios": "^1.3.1",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.4.0",
"@temporalio/activity": "^1.11.3",
"@temporalio/client": "^1.11.3",
"@temporalio/common": "^1.11.3",
"@temporalio/worker": "^1.11.3",
"@temporalio/workflow": "^1.11.3"
"@temporalio/activity": "^1.11.5",
"@temporalio/client": "^1.11.5",
"@temporalio/common": "^1.11.5",
"@temporalio/worker": "^1.11.5",
"@temporalio/workflow": "^1.11.5"
},
"devDependencies": {
"@nestjs/cli": "^8.1.3",
"@nestjs/schematics": "^8.0.4",
"@nestjs/testing": "^8.1.1",
"@temporalio/testing": "^1.11.3",
"@types/express": "^4.17.13",
"@types/jest": "^27.0.2",
"@types/node": "^16.11.1",
"@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "5.x",
"@typescript-eslint/parser": "5.x",
"eslint": "^7.32.0",
"@nestjs/cli": "^10.4.8",
"@nestjs/schematics": "^10.2.3",
"@nestjs/testing": "^10.4.8",
"@temporalio/testing": "^1.11.5",
"@types/express": "^5.0.0",
"@types/jest": "^29.5.14",
"@types/node": "^20.3.1",
"@types/supertest": "^6.0.2",
"@typescript-eslint/eslint-plugin": "8.15.0",
"@typescript-eslint/parser": "8.15.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^27.3.0",
"nodemon": "^2.0.12",
"jest": "^29.7.0",
"nodemon": "^3.1.7",
"prettier": "^2.8.8",
"source-map-support": "^0.5.20",
"source-map-support": "^0.5.21",
"supertest": "^6.1.6",
"ts-jest": "^27.0.7",
"ts-loader": "^9.2.6",
"ts-node": "^10.3.0",
"tsconfig-paths": "^3.11.0",
"typescript": "^4.4.4"
"ts-jest": "^29.2.5",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.6.3"
},
"jest": {
"moduleFileExtensions": [
Expand Down
Loading