swarthy/redis-semaphore

View on GitHub
src/utils/createEval.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { createHash } from 'crypto'
import createDebug from 'debug'
import { RedisClient } from '../types'

import { getConnectionName } from './index'

const debug = createDebug('redis-semaphore:eval')

function createSHA1(script: string) {
  return createHash('sha1').update(script, 'utf8').digest('hex')
}

function isNoScriptError(err: Error) {
  return err.toString().indexOf('NOSCRIPT') !== -1
}

export default function createEval<Args extends Array<number | string>, Result>(
  script: string,
  keysCount: number
) {
  const sha1 = createSHA1(script)
  debug('creating script:', script, 'sha1:', sha1)
  return async function optimizedEval(
    client: RedisClient,
    args: Args
  ): Promise<Result> {
    const connectionName = getConnectionName(client)
    const evalSHAArgs = [sha1, keysCount, ...args]
    debug(connectionName, sha1, 'attempt, args:', evalSHAArgs)
    try {
      return (await client.evalsha(sha1, keysCount, ...args)) as Promise<Result>
    } catch (err: any) {
      if (isNoScriptError(err)) {
        const evalArgs = [script, keysCount, ...args]
        debug(connectionName, sha1, 'fallback to eval, args:', evalArgs)
        return (await client.eval(
          script,
          keysCount,
          ...args
        )) as Promise<Result>
      } else {
        throw err
      }
    }
  }
}