node使用redlock分布式锁

'use strict';

const Service = require('egg').Service;
const moment = require('moment');
const redis = require('redis');
const RedlockClass = require('redlock');
const { port, host, password } = require('../../../config/config.default')({ getter: 'redis' }).client;

class BusinessHandlingService extends Service {
  // sql实例
  sqlClient() {
    return this.ctx.state.sqlClient || this.app.mysql.get(this.ctx.session.sqlName)
  }

  // redlock实例
  redlockClient() {
    // redis客户端
    const redisClient = redis.createClient(port, host, { password: password, db: '1' })
    redisClient.on('redisClient-err', err => { redisClient.quit() })

    const redlock = new RedlockClass(
      [redisClient],
      {
        driftFactor: 0.01, // 漂移值
        retryCount: 60, // 重试次数
        retryDelay: 500, // 重试间隔
        retryJitter: 200 // 间隔增量随机最大值
      }
    )

    return redlock
  }

  // 生成受理单号
  async createBusNo() {
    const { ctx } = this

    // 分布式锁
    const redlockClient = this.redlockClient()
    const flag = `createBus` // 锁名(场景唯一标识)
    const ttl =  1 * 30 * 1000 // 有效期(过期自动释放锁)
    const lock = await redlockClient.lock(flag, ttl).then(lock => lock).catch(err => false)
    if (!lock) {
      return { code: 1, msg: '【生成受理单号】系统繁忙,请稍后重试' }
    }

    // 新增号
    const nowDate = moment().format('YYYYMMDD')
    const lastNoRes = await this.sqlClient().query(`select substring(acceptNum, -4) as no from bus_accept_num where acceptNum is not null and substring(acceptNum, 1, 8) = '${nowDate}' order by (substring(acceptNum, -4)) desc limit 0, 1`)
    const no = lastNoRes.length ? +lastNoRes[0].no : 0
    const acceptNum = nowDate + ('' + (no + 1)).padStart(4, 0) // 202403180009

    // 记录号
    await this.sqlClient().insert('bus_accept_num', { acceptNum, acceptTime: moment().format('YYYY-MM-DD HH:mm:ss') })

    // 解锁
    lock.unlock()
    return { code: 0, data: { acceptNum }, msg: '受理单号生成成功' }
  }
}
posted @ 2024-03-19 10:30  _senjer  阅读(67)  评论(0)    收藏  举报