From 9aef1431cbefd8bf1fc48654c94cc464243e0113 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Tue, 15 Aug 2023 11:31:46 +0200 Subject: [PATCH] feat: smtp client pool example MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- .eslintrc.js | 1 + .github/dependabot.yml | 12 +++++ CHANGELOG.md | 1 + README.md | 1 + .../typescript/http-client-pool/src/main.ts | 2 +- .../typescript/smtp-client-pool/package.json | 30 +++++++++++ .../smtp-client-pool/pnpm-lock.yaml | 53 +++++++++++++++++++ .../typescript/smtp-client-pool/src/main.ts | 39 ++++++++++++++ .../typescript/smtp-client-pool/src/pool.ts | 24 +++++++++ .../typescript/smtp-client-pool/src/types.ts | 7 +++ .../typescript/smtp-client-pool/src/worker.ts | 18 +++++++ .../typescript/smtp-client-pool/tsconfig.json | 15 ++++++ 12 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 examples/typescript/smtp-client-pool/package.json create mode 100644 examples/typescript/smtp-client-pool/pnpm-lock.yaml create mode 100644 examples/typescript/smtp-client-pool/src/main.ts create mode 100644 examples/typescript/smtp-client-pool/src/pool.ts create mode 100644 examples/typescript/smtp-client-pool/src/types.ts create mode 100644 examples/typescript/smtp-client-pool/src/worker.ts create mode 100644 examples/typescript/smtp-client-pool/tsconfig.json diff --git a/.eslintrc.js b/.eslintrc.js index e2fc35b2..9bf41f26 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -81,6 +81,7 @@ module.exports = defineConfig({ 'req', 'resize', 'sinon', + 'smtp', 'threadjs', 'threadwork', 'tinypool', diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ee586d98..8fed0ddb 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -44,6 +44,18 @@ updates: - 'pioardi' - 'jerome-benoit' versioning-strategy: increase + - package-ecosystem: 'npm' + directory: '/examples/typescript/smtp-client-pool' + schedule: + interval: 'daily' + labels: + - 'dependencies' + - 'examples' + - 'nocombine' + reviewers: + - 'pioardi' + - 'jerome-benoit' + versioning-strategy: increase - package-ecosystem: 'npm' directory: '/examples/typescript/http-server-pool/express-worker_threads' schedule: diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d1da823..f897624e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add kill handler to worker options allowing to execute custom code when worker is killed. +- SMTP server pool example: nodemailer. ## [2.6.25] - 2023-08-13 diff --git a/README.md b/README.md index 50a2227c..abeb9f9f 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,7 @@ You can do the same with the classes _ClusterWorker_, _FixedClusterPool_ and _Dy - [Javascript](./examples/javascript/) - [Typescript](./examples/typescript/) - [HTTP client pool](./examples/typescript/http-client-pool/) + - [SMTP client pool](./examples/typescript/smtp-client-pool/) - [HTTP server pool](./examples/typescript/http-server-pool/) - [Express worker_threads pool](./examples/typescript/http-server-pool/express-worker_threads/) - [Fastify worker_threads pool](./examples/typescript/http-server-pool/fastify-worker_threads/) diff --git a/examples/typescript/http-client-pool/src/main.ts b/examples/typescript/http-client-pool/src/main.ts index f307bb62..8217434f 100644 --- a/examples/typescript/http-client-pool/src/main.ts +++ b/examples/typescript/http-client-pool/src/main.ts @@ -19,7 +19,7 @@ for (const workerFunction of ['node_fetch', 'fetch', 'axios']) { console.info( `Received in ${elapsedTime.toFixed(2)}ms an array with ${ responses.length - } responses from ${parallelism} parallel requests made with ${workerFunction} on ${requestUrl}:\n`, + } responses from ${parallelism} parallel requests made with HTTP client pool task function ${workerFunction} on ${requestUrl}:\n`, responses ) } catch (error) { diff --git a/examples/typescript/smtp-client-pool/package.json b/examples/typescript/smtp-client-pool/package.json new file mode 100644 index 00000000..c50a48fb --- /dev/null +++ b/examples/typescript/smtp-client-pool/package.json @@ -0,0 +1,30 @@ +{ + "$schema": "https://json.schemastore.org/package", + "name": "smtp-client-pool", + "version": "1.0.0", + "description": "SMTP client pool", + "main": "dist/main.js", + "type": "module", + "volta": { + "node": "20.5.1", + "pnpm": "8.6.12" + }, + "scripts": { + "build": "pnpm build:clean && tsc", + "build:clean": "tsc --build --clean", + "start": "node dist/main.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "nodemailer": "^6.9.4", + "poolifier": "^2.6.25" + }, + "devDependencies": { + "@types/node": "^20.5.0", + "@types/nodemailer": "^6.4.9", + "typescript": "^5.1.6" + } +} diff --git a/examples/typescript/smtp-client-pool/pnpm-lock.yaml b/examples/typescript/smtp-client-pool/pnpm-lock.yaml new file mode 100644 index 00000000..af7eebf0 --- /dev/null +++ b/examples/typescript/smtp-client-pool/pnpm-lock.yaml @@ -0,0 +1,53 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + nodemailer: + specifier: ^6.9.4 + version: 6.9.4 + poolifier: + specifier: ^2.6.25 + version: 2.6.25 + +devDependencies: + '@types/node': + specifier: ^20.5.0 + version: 20.5.0 + '@types/nodemailer': + specifier: ^6.4.9 + version: 6.4.9 + typescript: + specifier: ^5.1.6 + version: 5.1.6 + +packages: + + /@types/node@20.5.0: + resolution: {integrity: sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==} + dev: true + + /@types/nodemailer@6.4.9: + resolution: {integrity: sha512-XYG8Gv+sHjaOtUpiuytahMy2mM3rectgroNbs6R3djZEKmPNiIJwe9KqOJBGzKKnNZNKvnuvmugBgpq3w/S0ig==} + dependencies: + '@types/node': 20.5.0 + dev: true + + /nodemailer@6.9.4: + resolution: {integrity: sha512-CXjQvrQZV4+6X5wP6ZIgdehJamI63MFoYFGGPtHudWym9qaEHDNdPzaj5bfMCvxG1vhAileSWW90q7nL0N36mA==} + engines: {node: '>=6.0.0'} + dev: false + + /poolifier@2.6.25: + resolution: {integrity: sha512-e8RNC8txuDO7x1ALNMDTUVWyrsMCod3krp/ZIhR+L9Q0KpoywwHekyWnRB4V2PYW/B1yxvXoPbQi1a2hZOfsNw==} + engines: {node: '>=16.14.0', pnpm: '>=8.6.0'} + requiresBuild: true + dev: false + + /typescript@5.1.6: + resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} + engines: {node: '>=14.17'} + hasBin: true + dev: true diff --git a/examples/typescript/smtp-client-pool/src/main.ts b/examples/typescript/smtp-client-pool/src/main.ts new file mode 100644 index 00000000..70b1cb24 --- /dev/null +++ b/examples/typescript/smtp-client-pool/src/main.ts @@ -0,0 +1,39 @@ +import { smtpClientPool } from './pool.js' + +const tos = ['bar@example.com, baz@example.com'] + +const smtpClientPoolPromises = new Set>() +for (const to of tos) { + smtpClientPoolPromises.add( + smtpClientPool.execute({ + smtpTransport: { + host: 'smtp.domain.tld', + port: 465, + secure: true, + auth: { + user: 'REPLACE-WITH-YOUR-ALIAS@DOMAIN.TLD', + pass: 'REPLACE-WITH-YOUR-GENERATED-PASSWORD' + } + }, + mail: { + from: '"Foo" ', + to, + subject: 'Hello', + text: 'Hello world?', + html: 'Hello world?' + } + }) + ) +} +try { + const now = performance.now() + await Promise.all(smtpClientPoolPromises) + const elapsedTime = performance.now() - now + console.info( + `Send in parallel in ${elapsedTime.toFixed(2)}ms ${ + tos.length + } mails with SMTP client pool` + ) +} catch (error) { + console.error(error) +} diff --git a/examples/typescript/smtp-client-pool/src/pool.ts b/examples/typescript/smtp-client-pool/src/pool.ts new file mode 100644 index 00000000..f7309447 --- /dev/null +++ b/examples/typescript/smtp-client-pool/src/pool.ts @@ -0,0 +1,24 @@ +import { fileURLToPath } from 'node:url' +import { dirname, extname, join } from 'node:path' +import { DynamicThreadPool, availableParallelism } from 'poolifier' +import { type WorkerData } from './types.js' + +const workerFile = join( + dirname(fileURLToPath(import.meta.url)), + `worker${extname(fileURLToPath(import.meta.url))}` +) + +export const smtpClientPool = new DynamicThreadPool( + 1, + availableParallelism(), + workerFile, + { + enableTasksQueue: true, + tasksQueueOptions: { + concurrency: 8 + }, + errorHandler: (e: Error) => { + console.error('Thread worker error:', e) + } + } +) diff --git a/examples/typescript/smtp-client-pool/src/types.ts b/examples/typescript/smtp-client-pool/src/types.ts new file mode 100644 index 00000000..7287ad54 --- /dev/null +++ b/examples/typescript/smtp-client-pool/src/types.ts @@ -0,0 +1,7 @@ +import type Mail from 'nodemailer/lib/mailer/index.js' +import type SMTPTransport from 'nodemailer/lib/smtp-transport/index.js' + +export interface WorkerData { + smtpTransport: SMTPTransport.Options + mail: Mail.Options +} diff --git a/examples/typescript/smtp-client-pool/src/worker.ts b/examples/typescript/smtp-client-pool/src/worker.ts new file mode 100644 index 00000000..a6026e4b --- /dev/null +++ b/examples/typescript/smtp-client-pool/src/worker.ts @@ -0,0 +1,18 @@ +import { ThreadWorker } from 'poolifier' +import { createTransport } from 'nodemailer' +import type Mail from 'nodemailer/lib/mailer/index.js' +import { type WorkerData } from './types.js' + +class SmtpClientWorker extends ThreadWorker { + public constructor () { + super({ + nodemailer: async (workerData?: WorkerData) => { + await createTransport(workerData?.smtpTransport).sendMail( + workerData?.mail as Mail.Options + ) + } + }) + } +} + +export const smtpClientWorker = new SmtpClientWorker() diff --git a/examples/typescript/smtp-client-pool/tsconfig.json b/examples/typescript/smtp-client-pool/tsconfig.json new file mode 100644 index 00000000..57e49a1c --- /dev/null +++ b/examples/typescript/smtp-client-pool/tsconfig.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "Node16", + "verbatimModuleSyntax": true, + "rootDir": "./src", + "outDir": "./dist", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + } +} -- 2.34.1