JS – Semaphore

A veces no interesa evitar que muchas peticiones asíncronas se ejecuten en paralelo, por motivos de rendimiento limite de CPU o bien por lógica del programa que debe esperar a que finalice el bloque completo antes de permitir dejar pasar a la siguiente petición,

Para ello podemos crear un semáforo, que solo permitirá la ejecución del código de 1 e 1 (o de varios si se le configura)

Caso de uso: podemos tener un servidor express que recibe simultáneamente diferentes peticiones, pero una función que necesita ser ejecutado 1 a 1 sin poder ser concurrentes, por ejemplo comprimir un archivo y enviarlo

export class Semaphore {

    currentRequests: any[]
    runningRequests: number
    maxConcurrentRequests: number

    constructor(maxConcurrentRequests = 1) {
        this.currentRequests = [];
        this.runningRequests = 0;
        this.maxConcurrentRequests = maxConcurrentRequests;
    }


    callFunction<T>(fnToCall: () => Promise<T>, ...args: any): Promise<T> {
        return new Promise((resolve, reject) => {
            this.currentRequests.push({
                resolve,
                reject,
                fnToCall,
                args,
            });
            this.tryNext();
        });
    }

    tryNext() {
        if (!this.currentRequests.length) {
            return;
        } else if (this.runningRequests < this.maxConcurrentRequests) {
            let { resolve, reject, fnToCall, args } = this.currentRequests.shift();
            this.runningRequests++;
            let req = fnToCall(...args);
            req.then((res: any) => resolve(res))
                .catch((err: any) => reject(err))
                .finally(() => {
                    this.runningRequests--;
                    this.tryNext();
                });
        }
    }
}

Forma de uso:

// Funcion genérica que devuelve una promesa
const compress = (encoding: string, md5: string): Promise<string> => {
    return new Promise((resolve, reject) => {
        // do stuff
    })
}

...

// Llamada a la función "callFunction"
const throttler = new Semaphore(1);
throttler.callFunction(() => compress('codec', 'xxx'))
throttler.callFunction(() => compress('codec', 'xxx'))
throttler.callFunction(() => compress('codec', 'xxx'))
throttler.callFunction(() => compress('codec', 'xxx'))

Fuente original: https://medium.com/swlh/semaphores-in-javascript-e415b0d684bc

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.