Skip to content

Commit

Permalink
Merge pull request #24 from BAXUSNFT/main
Browse files Browse the repository at this point in the history
fix: register client async method
  • Loading branch information
KurtzL authored Nov 15, 2022
2 parents 30a232e + 499aaf6 commit 47b9143
Show file tree
Hide file tree
Showing 17 changed files with 192 additions and 56 deletions.
14 changes: 14 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# don't ever lint node_modules
node_modules

# don't lint build output (make sure it's set to your correct build folder name)
dist

# don't lint nyc coverage output
coverage

.eslintrc.js

.babel.config.js

lib/**/*.spec.ts
29 changes: 14 additions & 15 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
module.exports = {
parser: "@typescript-eslint/parser",
parser: '@typescript-eslint/parser',
parserOptions: {
project: "tsconfig.json",
sourceType: "module",
project: 'tsconfig.json',
sourceType: 'module',
},
plugins: ["@typescript-eslint/eslint-plugin"],
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"prettier/@typescript-eslint",
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
],
root: true,
env: {
node: true,
jest: true,
},
rules: {
"@typescript-eslint/interface-name-prefix": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/ban-types": "off",
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/ban-types': 'off',
},
};
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export class AppController {

## Advanced Options

- Creating the Worker connection:
```ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
Expand Down Expand Up @@ -132,11 +133,41 @@ import * as path from 'path';
};
},
}),
ClientModule,
],
})
export class AppModule {}
```

- Creating the client connection:
```ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TemporalModule } from 'nestjs-temporal';
import { Connection } from '@temporalio/client';

@Module({
imports: [
TempModule.registerClientAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (config: ConfigService) => {
const temporalHost = config.get('app.temporalHost');
const connection = await Connection.connect({
address: temporalHost,
});

return {
connection,
};
},
}),
],
})
export class ClientModule {}
```


## People

- Author - [Zegue kurt](https://github.com/KurtzL)
Expand Down
1 change: 1 addition & 0 deletions lib/interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './shared-worker-config.interface';
export * from './shared-runtime-config.interface';
export * from './shared-connection-config.interface';
export * from './temporal-module.interface';
export * from './shared-workflow-client-options.interface';
4 changes: 4 additions & 0 deletions lib/interfaces/shared-connection-config.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export interface SharedConnectionAsyncConfiguration
* Factory function that returns an instance of the provider to be injected.
*/
useFactory?: (...args: any[]) => Promise<NativeConnectionOptions> | NativeConnectionOptions;
/**
* Instance of a provider to be injected.
*/
useValue?: NativeConnectionOptions;
/**
* Optional list of providers to be injected into the context of the Factory function.
*/
Expand Down
4 changes: 4 additions & 0 deletions lib/interfaces/shared-runtime-config.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export interface SharedRuntimeAsyncConfiguration
* Factory function that returns an instance of the provider to be injected.
*/
useFactory?: (...args: any[]) => Promise<RuntimeOptions> | RuntimeOptions;
/**
* Instance of a provider to be injected.
*/
useValue?: RuntimeOptions;
/**
* Optional list of providers to be injected into the context of the Factory function.
*/
Expand Down
4 changes: 4 additions & 0 deletions lib/interfaces/shared-worker-config.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export interface SharedWorkerAsyncConfiguration
* Factory function that returns an instance of the provider to be injected.
*/
useFactory?: (...args: any[]) => Promise<WorkerOptions> | WorkerOptions;
/**
* Instance of a provider to be injected.
*/
useValue?: WorkerOptions;
/**
* Optional list of providers to be injected into the context of the Factory function.
*/
Expand Down
31 changes: 31 additions & 0 deletions lib/interfaces/shared-workflow-client-options.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { FactoryProvider, ModuleMetadata, Type } from '@nestjs/common';
import { WorkflowClientOptions } from '@temporalio/client';

export interface SharedWorkflowClientOptionsFactory {
createSharedConfiguration(): Promise<WorkflowClientOptions> | WorkflowClientOptions;
}

export interface SharedWorkflowClientOptions
extends Pick<ModuleMetadata, 'imports'> {
name?: string;
/**
* Existing Provider to be used.
*/
useExisting?: Type<SharedWorkflowClientOptionsFactory>;
/**
* Type (class name) of provider (instance to be registered and injected).
*/
useClass?: Type<SharedWorkflowClientOptionsFactory>;
/**
* Factory function that returns an instance of the provider to be injected.
*/
useFactory?: (...args: any[]) => Promise<WorkflowClientOptions> | WorkflowClientOptions;
/**
* Instance of a provider to be injected.
*/
useValue?: WorkflowClientOptions;
/**
* Optional list of providers to be injected into the context of the Factory function.
*/
inject?: FactoryProvider['inject'];
}
2 changes: 1 addition & 1 deletion lib/temporal.explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export class TemporalExplorer
if (this.metadataAccessor.isActivity(instance[key])) {
const metadata = this.metadataAccessor.getActivity(instance[key]);

let args: unknown[] = [metadata?.name];
const args: unknown[] = [metadata?.name];

if (isRequestScoped) {
// TODO: handle request scoped
Expand Down
45 changes: 18 additions & 27 deletions lib/temporal.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ import { TemporalExplorer } from './temporal.explorer';
import {
SharedWorkerAsyncConfiguration,
TemporalModuleOptions,
SharedRuntimeAsyncConfiguration,
SharedConnectionAsyncConfiguration,
SharedWorkflowClientOptions,
} from './interfaces';
import {
TEMPORAL_CORE_CONFIG,
TEMPORAL_WORKER_CONFIG,
TEMPORAL_CONNECTION_CONFIG,
} from './temporal.constants';
import { createClientProviders } from './temporal.providers';
import { SharedRuntimeAsyncConfiguration } from './interfaces/shared-runtime-config.interface';
import { SharedConnectionAsyncConfiguration } from './interfaces/shared-connection-config.interface';
import { createAsyncProvider, createClientAsyncProvider } from './utils';

@Module({})
export class TemporalModule {
Expand Down Expand Up @@ -63,12 +65,12 @@ export class TemporalModule {
asyncRuntimeConfig?: SharedRuntimeAsyncConfiguration,
): DynamicModule {
const providers: Provider[] = [
this.createAsyncProvider(TEMPORAL_WORKER_CONFIG, asyncWorkerConfig),
this.createAsyncProvider(
createAsyncProvider(TEMPORAL_WORKER_CONFIG, asyncWorkerConfig),
createAsyncProvider(
TEMPORAL_CONNECTION_CONFIG,
asyncConnectionConfig,
),
this.createAsyncProvider(TEMPORAL_CORE_CONFIG, asyncRuntimeConfig),
createAsyncProvider(TEMPORAL_CORE_CONFIG, asyncRuntimeConfig),
];

return {
Expand All @@ -80,26 +82,6 @@ export class TemporalModule {
};
}

private static createAsyncProvider(
provide: string,
options?:
| SharedWorkerAsyncConfiguration
| SharedRuntimeAsyncConfiguration
| SharedConnectionAsyncConfiguration,
): Provider {
if (options?.useFactory) {
return {
provide,
useFactory: options.useFactory,
inject: options.inject || [],
};
}
return {
provide,
useValue: null,
} as Provider;
}

static registerClient(options?: TemporalModuleOptions): DynamicModule {
const createClientProvider = createClientProviders([].concat(options));
return {
Expand All @@ -109,8 +91,17 @@ export class TemporalModule {
exports: createClientProvider,
};
}
static registerClientAsync(options: TemporalModuleOptions): DynamicModule {
throw new Error('Method not implemented.');
static registerClientAsync(
asyncSharedWorkflowClientOptions: SharedWorkflowClientOptions
): DynamicModule {
const providers = createClientAsyncProvider(asyncSharedWorkflowClientOptions);

return {
global: true,
module: TemporalModule,
providers,
exports: providers,
};
}

private static registerCore() {
Expand Down
15 changes: 4 additions & 11 deletions lib/temporal.providers.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,24 @@
import { OnApplicationShutdown, Provider } from '@nestjs/common';
import { Provider } from '@nestjs/common';
import { Connection, WorkflowClient } from '@temporalio/client';

import { TemporalModuleOptions } from './interfaces';
import { getQueueToken } from './utils';
import { getQueueToken, getWorkflowClient } from './utils';

export async function buildClient(
option: TemporalModuleOptions,
): Promise<WorkflowClient> {
const connection = await Connection.connect(option.connection);
const client = new WorkflowClient({
return getWorkflowClient({
...option.workflowOptions,
connection,
});

(connection as any as OnApplicationShutdown).onApplicationShutdown =
function (this: Connection) {
return this.client.close();
};

return client;
}

export function createClientProviders(
options: TemporalModuleOptions[],
): Provider[] {
return options.map((option) => ({
provide: getQueueToken(option && option.name ? option.name : undefined),
provide: getQueueToken(option?.name || undefined),
useFactory: async () => {
return buildClient(option || {});
},
Expand Down
12 changes: 12 additions & 0 deletions lib/utils/client.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { OnApplicationShutdown } from "@nestjs/common";
import { WorkflowClient, WorkflowClientOptions } from "@temporalio/client";

export function assignOnAppShutdownHook(client: WorkflowClient) {
(client as unknown as OnApplicationShutdown).onApplicationShutdown = client.connection.close;
return client;
}

export function getWorkflowClient(options?: WorkflowClientOptions) {
const client = new WorkflowClient(options);
return assignOnAppShutdownHook(client);
}
4 changes: 4 additions & 0 deletions lib/utils/get-queue-token.util.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
export function getQueueToken(name?: string): string {
return name ? `TemporalQueue_${name}` : 'TemporalQueue_default';
}

export function getAsyncQueueToken(name?: string): string {
return name ? `TemporalAsyncQueue_${name}` : 'TemporalAsyncQueue_default';
}
2 changes: 2 additions & 0 deletions lib/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from './get-queue-options-token.util';
export * from './get-shared-config-token.util';
export * from './get-queue-token.util';
export * from './client.util';
export * from './provider.util';
45 changes: 45 additions & 0 deletions lib/utils/provider.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Provider } from "@nestjs/common";
import { WorkflowClientOptions } from "@temporalio/client";

import { SharedWorkflowClientOptions } from "../interfaces/shared-workflow-client-options.interface";
import { SharedConnectionAsyncConfiguration, SharedRuntimeAsyncConfiguration, SharedWorkerAsyncConfiguration } from "../interfaces";
import { getWorkflowClient } from "./client.util";
import { getAsyncQueueToken, getQueueToken } from "./get-queue-token.util";

export function createAsyncProvider(
provide: string,
options?:
| SharedWorkerAsyncConfiguration
| SharedRuntimeAsyncConfiguration
| SharedConnectionAsyncConfiguration
| SharedWorkflowClientOptions,
): Provider {
if (options?.useFactory) {
const { useFactory, inject } = options;
return {
provide,
useFactory,
inject: inject || [],
};
}
return {
provide,
useValue: options?.useValue || null,
};
}

export function createClientAsyncProvider(
asyncOptions: SharedWorkflowClientOptions,
): Provider[] {
const name = asyncOptions.name ? asyncOptions.name : undefined;
const optionsProvide = getAsyncQueueToken(name)
const clientProvide = getQueueToken(name);
return [
createAsyncProvider(optionsProvide, asyncOptions),
{
provide: clientProvide,
useFactory: (options?: WorkflowClientOptions) => getWorkflowClient(options),
inject: [optionsProvide],
},
];
}
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 47b9143

Please sign in to comment.