From 7e0dba1c278b639192afb93ee90c0ec57716fdfc Mon Sep 17 00:00:00 2001 From: getlarge Date: Sat, 13 Jul 2024 13:57:03 +0200 Subject: [PATCH] docs: add examples [skip ci] --- packages/amqp-transport/README.md | 13 ++- .../test/amqp.integration.spec.ts | 38 ++++----- .....ts => dummy-consumer.controller.mock.ts} | 0 packages/async-local-storage/README.md | 4 +- packages/cluster/README.md | 84 ++++++++++++++++++- packages/fastify-upload/README.md | 4 +- packages/file-storage/README.md | 10 ++- packages/lock/README.md | 4 +- 8 files changed, 123 insertions(+), 34 deletions(-) rename packages/amqp-transport/test/{dummy-consumer.controller.mock..ts => dummy-consumer.controller.mock.ts} (100%) diff --git a/packages/amqp-transport/README.md b/packages/amqp-transport/README.md index bd3ae00..3260bfe 100644 --- a/packages/amqp-transport/README.md +++ b/packages/amqp-transport/README.md @@ -1,12 +1,17 @@ -# AMQP-Transport +# AMQP Transport [![npm][npm-image]][npm-url] [npm-image]: https://img.shields.io/npm/v/@getlarge/nestjs-tools-amqp-transport.svg?style=flat [npm-url]: https://npmjs.org/package/@getlarge/nestjs-tools-amqp-transport -Custom AMQP strategies for Nest microservice transport. -Supports : +A custom AMQP strategy for Nest microservice transport, which extends NestJS AMQP [producer](https://github.com/nestjs/nest/blob/master/packages/microservices/client/client-rmq.ts) and [consumer](https://github.com/nestjs/nest/blob/master/packages/microservices/server/server-rmq.ts) by adding support for: - exchanges -- assert reply queue +- reply queue assertion + +By enabling exchanges you can broadcast messages to multiple queues, and by asserting reply queue you can ensure that reply queue with static name exists. + +## Example + +The integration tests contain an [example consumer](./test/dummy-consumer.controller.mock.ts) and [example producer](./test/dummy-producer.service.mock.ts) that demonstrate how to use this library. diff --git a/packages/amqp-transport/test/amqp.integration.spec.ts b/packages/amqp-transport/test/amqp.integration.spec.ts index 2366ff6..d4606db 100644 --- a/packages/amqp-transport/test/amqp.integration.spec.ts +++ b/packages/amqp-transport/test/amqp.integration.spec.ts @@ -10,7 +10,7 @@ import { setTimeout } from 'node:timers/promises'; import { AmqpClient, AmqpOptions, AmqpServer } from '../src'; import { DUMMY_CLIENT, DUMMY_QUEUE, RMQ_URL } from './dummy.constants'; -import { DummyConsumerController } from './dummy-consumer.controller.mock.'; +import { DummyConsumerController } from './dummy-consumer.controller.mock'; import { DummyProducerService } from './dummy-producer.service.mock'; interface Closeable { @@ -170,7 +170,7 @@ describe('AMQP tests', () => { producers: [moduleProducer], } = await setupAll(); const msg = { message }; - const service = moduleProducer.get(DummyProducerService); + const service = moduleProducer.get(DummyProducerService); // Then const result = await service.test(msg); @@ -186,7 +186,7 @@ describe('AMQP tests', () => { producers: [moduleProducer], } = await setupAll(); const msg = { message }; - const service = moduleProducer.get(DummyProducerService); + const service = moduleProducer.get(DummyProducerService); // Then const results = await makeMultipleRequests(() => service.test(msg), 5); // Expect @@ -206,7 +206,7 @@ describe('AMQP tests', () => { producers: [moduleProducer], } = await setupAll({ testConfiguration: { noAck } }); const msg = { message }; - const service = moduleProducer.get(DummyProducerService); + const service = moduleProducer.get(DummyProducerService); // Then const result = await service.test(msg, noAck); expect(result).toBeDefined(); @@ -222,7 +222,7 @@ describe('AMQP tests', () => { producers: [moduleProducer], } = await setupAll({ testConfiguration: { noAck } }); const msg = { message }; - const service = moduleProducer.get(DummyProducerService); + const service = moduleProducer.get(DummyProducerService); // Then const results = await makeMultipleRequests(() => service.test({ message }, noAck), 5); // Expect @@ -242,7 +242,7 @@ describe('AMQP tests', () => { const { producers: [moduleProducer], } = await setupAll({ testConfiguration: { noAck } }); - const service = moduleProducer.get(DummyProducerService); + const service = moduleProducer.get(DummyProducerService); // Then const result = await service.test(msg, noAck); expect(result).toBeDefined(); @@ -258,7 +258,7 @@ describe('AMQP tests', () => { const { producers: [moduleProducer], } = await setupAll({ testConfiguration: { noAck } }); - const service = moduleProducer.get(DummyProducerService); + const service = moduleProducer.get(DummyProducerService); // Then const results = await makeMultipleRequests(() => service.test(msg, noAck), 5); // Expect @@ -280,7 +280,7 @@ describe('AMQP tests', () => { } = await setupAll({ testConfiguration: { noAck, prefetchCount: 5 }, }); - const service = moduleProducer.get(DummyProducerService); + const service = moduleProducer.get(DummyProducerService); // Then const results = await makeMultipleRequests(() => service.test(msg, noAck), 10); // Expect @@ -302,7 +302,7 @@ describe('AMQP tests', () => { } = await setupAll({ testConfiguration: { noAck, prefetchCount: 5 }, }); - const service = moduleProducer.get(DummyProducerService); + const service = moduleProducer.get(DummyProducerService); // Then const result = await service.test(msg, noAck); expect(result).toBeDefined(); @@ -318,7 +318,7 @@ describe('AMQP tests', () => { } = await setupAll({ testConfiguration: { noAck, prefetchCount: 5, isGlobalPrefetchCount: true }, }); - const service = moduleProducer.get(DummyProducerService); + const service = moduleProducer.get(DummyProducerService); // Then const results = await makeMultipleRequests(() => service.test(msg, noAck), 5); // Expect @@ -338,7 +338,7 @@ describe('AMQP tests', () => { } = await setupAll({ testConfiguration: { noAck, prefetchCount: 5, isGlobalPrefetchCount: true }, }); - const service = moduleProducer.get(DummyProducerService); + const service = moduleProducer.get(DummyProducerService); // Then const results = await makeMultipleRequests(() => service.test(msg, noAck), 5); // Expect @@ -357,7 +357,7 @@ describe('AMQP tests', () => { testConfiguration: { noAck, prefetchCount: 1 }, consumersCount: 2, }); - const service = moduleProducer.get(DummyProducerService); + const service = moduleProducer.get(DummyProducerService); // Then const results = await makeMultipleRequests(() => service.getConsumerWorkerId(noAck), 20); // Expect @@ -376,8 +376,8 @@ describe('AMQP tests', () => { testConfiguration: { noAck, prefetchCount: 1 }, producersCount: 2, }); - const service1 = moduleProducer1.get(DummyProducerService); - const service2 = moduleProducer2.get(DummyProducerService); + const service1 = moduleProducer1.get(DummyProducerService); + const service2 = moduleProducer2.get(DummyProducerService); // Then const resultsMatrix = await Promise.all([ makeMultipleRequests(() => service1.test(msg, noAck), 10), @@ -411,8 +411,8 @@ describe('AMQP tests', () => { }, producersCount: 2, }); - const service1 = moduleProducer1.get(DummyProducerService); - const service2 = moduleProducer2.get(DummyProducerService); + const service1 = moduleProducer1.get(DummyProducerService); + const service2 = moduleProducer2.get(DummyProducerService); // Then const resultsMatrix = await Promise.all([ makeMultipleRequests(() => service1.test(msg, noAck), 10), @@ -446,7 +446,7 @@ describe('AMQP tests', () => { }, producersCount: 1, }); - const service1 = moduleProducer1.get(DummyProducerService); + const service1 = moduleProducer1.get(DummyProducerService); // Then const resultsMatrix = await Promise.all([makeMultipleRequests(() => service1.test(msg, noAck), 10)]); // Expect @@ -473,8 +473,8 @@ describe('AMQP tests', () => { }, producersCount: 2, }); - const service1 = moduleProducer1.get(DummyProducerService); - const service2 = moduleProducer2.get(DummyProducerService); + const service1 = moduleProducer1.get(DummyProducerService); + const service2 = moduleProducer2.get(DummyProducerService); // Then await Promise.all([ makeMultipleRequests(() => service1.test(msg, noAck), 5), diff --git a/packages/amqp-transport/test/dummy-consumer.controller.mock..ts b/packages/amqp-transport/test/dummy-consumer.controller.mock.ts similarity index 100% rename from packages/amqp-transport/test/dummy-consumer.controller.mock..ts rename to packages/amqp-transport/test/dummy-consumer.controller.mock.ts diff --git a/packages/async-local-storage/README.md b/packages/async-local-storage/README.md index 7551ee7..09bf0b8 100644 --- a/packages/async-local-storage/README.md +++ b/packages/async-local-storage/README.md @@ -1,4 +1,4 @@ -# Async Local Storage` +# Async Local Storage [![npm][npm-image]][npm-url] @@ -54,3 +54,5 @@ assert(typeof requestContext.type === 'string'); service.delete('username'); ``` + + diff --git a/packages/cluster/README.md b/packages/cluster/README.md index c78738e..097d848 100644 --- a/packages/cluster/README.md +++ b/packages/cluster/README.md @@ -1,6 +1,86 @@ -# nestjs-tools-cluster +# Cluster -This library was generated with [Nx](https://nx.dev). +[![npm][npm-image]][npm-url] + +[npm-image]: https://img.shields.io/npm/v/@getlarge/nestjs-tools-cluster.svg?style=flat +[npm-url]: https://npmjs.org/package/@getlarge/nestjs-tools-cluster + +This package provides a simple way to clusterize a NestJS application. +The `ClusterService` class is a wrapper around the native `cluster` module and provides a simple API to manage the workers' lifecycle. + +## Installation + +```bash +$ npm install --save @getlarge/nestjs-tools-cluster +``` + +## Example + +```ts +import { Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { NestFactory } from '@nestjs/core'; +import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; +import { ClusterService, ClusterServiceConfig } from '@getlarge/cluster-service'; +import { cpus } from 'node:os'; + +import { AppModule } from './app/app.module'; + +const GLOBAL_API_PREFIX = 'api'; +const DEFAULT_PORT = 3000; +const CLUSTER_MODE = process.env.CLUSTER_MODE === 'true'; +const MAX_WORKERS = +process.env.MAX_WORKERS || cpus().length; + +async function bootstrap( + opts: { workerId?: number } = {}, + disconnect: () => void = () => process.exit(1), +): Promise { + /** + * This is a global variable that will be used to identify the worker id + * in the application. This is useful for debugging purposes. + */ + globalThis.__WORKER_ID__ = opts.workerId; + + try { + const app = await NestFactory.create( + AppModule, + new FastifyAdapter({ + trustProxy: true, + bodyLimit: +process.env.MAX_PAYLOAD_SIZE || 1048576, + }), + { bufferLogs: true, abortOnError: false }, + ); + app.setGlobalPrefix(GLOBAL_API_PREFIX); + const configService = app.get(ConfigService); + const port = configService.get('PORT', { infer: true }) ?? DEFAULT_PORT; + + await app.listen(port, '0.0.0.0', () => { + Logger.log(`Listening at http://localhost:${port}/${GLOBAL_API_PREFIX}`); + }); + } catch (error) { + Logger.error(error); + disconnect(); + } +} + +if (CLUSTER_MODE) { + const clusterConfig: ClusterServiceConfig = { + workers: MAX_WORKERS, + delay: 2000, + grace: 1000, + }; + + const clusterService = new ClusterService(clusterConfig); + clusterService.clusterize(bootstrap).catch((e) => { + clusterService.logger.error(e); + process.exit(1); + }); +} else { + void bootstrap({}, () => { + process.exit(1); + }); +} +``` ## Building diff --git a/packages/fastify-upload/README.md b/packages/fastify-upload/README.md index d78f559..97b5e24 100644 --- a/packages/fastify-upload/README.md +++ b/packages/fastify-upload/README.md @@ -5,10 +5,10 @@ [npm-image]: https://img.shields.io/npm/v/@getlarge/nestjs-tools-fastify-upload.svg?style=flat [npm-url]: https://npmjs.org/package/@getlarge/nestjs-tools-fastify-upload -The Fastify Upload Service provides file upload support for NestJS applications using the Fastify adapter. +This library provides file upload support for NestJS applications using the Fastify adapter. It uses the [@fastify/multipart](https://www.npmjs.com/package/@fastify/multipart) module. -The [nestjs-tools-file-storage](../file-storage/README.md) library can store the uploaded files in various storage backends. +It can be used in combintation of the [nestjs-tools-file-storage](../file-storage/README.md) library to store the uploaded files in various storage backends. Read [this issue](https://github.com/getlarge/nestjs-tools/issues/71) to understand why this library was created. diff --git a/packages/file-storage/README.md b/packages/file-storage/README.md index 3a91556..ddd3f5b 100644 --- a/packages/file-storage/README.md +++ b/packages/file-storage/README.md @@ -5,11 +5,13 @@ [npm-image]: https://img.shields.io/npm/v/@getlarge/nestjs-tools-file-storage.svg?style=flat [npm-url]: https://npmjs.org/package/@getlarge/nestjs-tools-file-storage -File storage classes for : +This module provide a unified API to store files in different storage providers. -- Node FileSystem -- Amazon S3 -- Google Cloud Storage +Supoorted backends: + +- [Node FileSystem](./src/lib/file-storage-fs.class.ts) +- [AWS S3](./src/lib/file-storage-s3.class.ts) +- [Google Cloud Storage](./src/lib/file-storage-google.class.ts) ## Installation diff --git a/packages/lock/README.md b/packages/lock/README.md index a4110ed..e36d380 100644 --- a/packages/lock/README.md +++ b/packages/lock/README.md @@ -20,12 +20,12 @@ $ npm install --save @getlarge/nestjs-tools-lock ```ts import { LockService } from '@getlarge/nestjs-tools-lock'; -import { Inject, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { Cron } from '@nestjs/schedule'; @Injectable() export class TasksService implements OnModuleDestroy { - constructor(@Inject(LockService) private lockService: LockService) {} + constructor(private lockService: LockService) {} onModuleDestroy() { this.lockService.close();