diff --git a/source/routes/index.ts b/source/routes/index.ts index 1a8e65d..638029c 100644 --- a/source/routes/index.ts +++ b/source/routes/index.ts @@ -1,8 +1,9 @@ import type { FastifyInstance, FastifyPluginAsync } from 'fastify' -import cpu from './cpu.ts' -import io from './io.ts' -import mem from './mem.ts' -import ping from './ping.ts' +import cpu from './load/cpu.ts' +import io from './load/io.ts' +import mem from './load/mem.ts' +import ping from './load/ping.ts' +import limitedConnectionsPool from './problems/connectionsPool.ts' // eslint-disable-next-line jsdoc/require-jsdoc const routes: FastifyPluginAsync = async (fastify: FastifyInstance) => { @@ -10,6 +11,7 @@ const routes: FastifyPluginAsync = async (fastify: FastifyInstance) => { void fastify.register(cpu) void fastify.register(mem) void fastify.register(io) + void fastify.register(limitedConnectionsPool) } export default routes diff --git a/source/routes/problems/connectionsPool.ts b/source/routes/problems/connectionsPool.ts new file mode 100644 index 0000000..1e5057a --- /dev/null +++ b/source/routes/problems/connectionsPool.ts @@ -0,0 +1,57 @@ +import type { FastifyPluginAsync } from 'fastify' +import { delayResponse } from '~/simulate/load.ts' + +const MAX_CONCURRENT_CONNECTIONS = 5 + +class ConnectionsPool { + private readonly maxConnections: number + private currentConnections: number + private readonly queue: Array<(value: string) => void> + + constructor(maxConnections: number) { + this.maxConnections = maxConnections + this.currentConnections = 0 + this.queue = [] + } + + async acquire(): Promise { + if (this.currentConnections < this.maxConnections) { + this.currentConnections++ + await Promise.resolve() + return + } + + await new Promise((resolve) => { + this.queue.push(resolve) + }) + } + + release(): void { + this.currentConnections-- + if (this.queue.length > 0) { + const next = this.queue.shift() + if (next) { + this.currentConnections++ + next('work') + } + } + } +} + +const pool = new ConnectionsPool(MAX_CONCURRENT_CONNECTIONS) + +// eslint-disable-next-line jsdoc/require-jsdoc +export const limitedConnectionsPool: FastifyPluginAsync = async (fastify) => { + fastify.get<{ Params: { ms: string } }>('/problems/limited-connections/pool/:ms', async (request) => { + try { + await pool.acquire() + + // Simulate some work + return await delayResponse(Number.parseInt(request.params.ms, 10)) + } finally { + pool.release() + } + }) +} + +export default limitedConnectionsPool diff --git a/source/simulate/load.ts b/source/simulate/load.ts index 50853bf..c84d862 100644 --- a/source/simulate/load.ts +++ b/source/simulate/load.ts @@ -1,7 +1,7 @@ import fs from 'node:fs/promises' import os from 'node:os' import path from 'node:path' -import { parseSize } from '../utils/parseSize.ts' +import { parseSize } from '~/utils/parseSize.ts' const MAX_DELAY = 5000 const memoryLeaks: unknown[] = []