feat: smtp client pool example
authorJérôme Benoit <jerome.benoit@sap.com>
Tue, 15 Aug 2023 09:31:46 +0000 (11:31 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Tue, 15 Aug 2023 09:31:46 +0000 (11:31 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
12 files changed:
.eslintrc.js
.github/dependabot.yml
CHANGELOG.md
README.md
examples/typescript/http-client-pool/src/main.ts
examples/typescript/smtp-client-pool/package.json [new file with mode: 0644]
examples/typescript/smtp-client-pool/pnpm-lock.yaml [new file with mode: 0644]
examples/typescript/smtp-client-pool/src/main.ts [new file with mode: 0644]
examples/typescript/smtp-client-pool/src/pool.ts [new file with mode: 0644]
examples/typescript/smtp-client-pool/src/types.ts [new file with mode: 0644]
examples/typescript/smtp-client-pool/src/worker.ts [new file with mode: 0644]
examples/typescript/smtp-client-pool/tsconfig.json [new file with mode: 0644]

index e2fc35b2c1264d4c08e5af3de0a3cc3fb36d924b..9bf41f268ea143ee9841e6575ac2f6c9223aa8fd 100644 (file)
@@ -81,6 +81,7 @@ module.exports = defineConfig({
           'req',
           'resize',
           'sinon',
+          'smtp',
           'threadjs',
           'threadwork',
           'tinypool',
index ee586d988c8a9dba808f549c0f9e2a9f31e4924c..8fed0ddb2b1b36871b75a51878d25e3db6572609 100644 (file)
@@ -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:
index 8d1da82330d9378b9eb1705c90269beb8625ddce..f897624e45e4391fb891ad90d10b6e05b27cb3e0 100644 (file)
@@ -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
 
index 50a2227c27209680a44eae3efcb5c8f5437325a8..abeb9f9f4386ead4df1597192dbadadc683c6923 100644 (file)
--- 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/)
index f307bb622ca7e5dbe549be2fffe33991e0caa547..8217434fddd4af8cf4b3c6b3a2722c373bda2494 100644 (file)
@@ -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 (file)
index 0000000..c50a48f
--- /dev/null
@@ -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 (file)
index 0000000..af7eebf
--- /dev/null
@@ -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 (file)
index 0000000..70b1cb2
--- /dev/null
@@ -0,0 +1,39 @@
+import { smtpClientPool } from './pool.js'
+
+const tos = ['bar@example.com, baz@example.com']
+
+const smtpClientPoolPromises = new Set<Promise<unknown>>()
+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" <foo@domain.tld>',
+        to,
+        subject: 'Hello',
+        text: 'Hello world?',
+        html: '<b>Hello world?</b>'
+      }
+    })
+  )
+}
+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 (file)
index 0000000..f730944
--- /dev/null
@@ -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<WorkerData>(
+  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 (file)
index 0000000..7287ad5
--- /dev/null
@@ -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 (file)
index 0000000..a6026e4
--- /dev/null
@@ -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<WorkerData> {
+  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 (file)
index 0000000..57e49a1
--- /dev/null
@@ -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
+  }
+}