hwj-common-lib
Version:
微信小程序云开发通用模块库,支持灵活的环境配置
208 lines (178 loc) • 5.13 kB
JavaScript
const cloud = require('wx-server-sdk')
const { CLOUD_ENV, CACHE } = require('./env')
const { BusinessError } = require('./error')
// 初始化云开发环境
cloud.init({
env: CLOUD_ENV
})
// 获取数据库实例
const db = cloud.database()
class Cache {
constructor(namespace) {
this.namespace = namespace
this.db = db.collection('cache')
}
// 生成缓存key
_generateKey(key) {
return `${this.namespace}:${key}`
}
// 设置缓存
async set(key, value, ttl = CACHE.TTL.MEDIUM) {
const cacheKey = this._generateKey(key)
const expireAt = new Date(Date.now() + ttl * 1000)
// 深度处理对象,移除所有 MongoDB 内部字段
const processValue = (val) => {
if (Array.isArray(val)) {
return val.map(item => processValue(item))
}
if (val && typeof val === 'object') {
const processed = {}
for (const [k, v] of Object.entries(val)) {
// 跳过 MongoDB 内部字段和 null/undefined 值
if (!k.startsWith('_') && v != null) {
processed[k] = processValue(v)
}
}
return processed
}
return val
}
const cacheValue = processValue(value)
try {
// 先删除旧的缓存
await this.del(key)
// 生成唯一的缓存文档ID
const cacheId = `${cacheKey}_${Date.now()}`
// 创建新的缓存文档
await this.db.add({
data: {
_id: cacheId, // 显式设置文档ID
cacheKey,
value: cacheValue,
expireAt,
createTime: db.serverDate(),
updateTime: db.serverDate()
}
})
return true
} catch (error) {
console.error('设置缓存失败:', error)
// 如果是重复键的错误,尝试更新
if (error.errCode === -501007) {
try {
await this.db.where({
cacheKey
}).update({
data: {
value: cacheValue,
expireAt,
updateTime: db.serverDate()
}
})
return true
} catch (updateError) {
console.error('更新缓存失败:', updateError)
throw new BusinessError(`更新缓存失败:${updateError.message}`)
}
}
throw new BusinessError(`设置缓存失败:${error.message}`)
}
}
// 获取缓存
async get(key) {
const cacheKey = this._generateKey(key)
try {
const { data } = await this.db.where({
cacheKey
}).get()
if (!data || data.length === 0) {
return null
}
const cache = data[0]
// 检查是否过期
if (cache && new Date(cache.expireAt) > new Date()) {
return cache.value
}
// 过期则删除
if (cache) {
await this.del(key)
}
return null
} catch (error) {
console.error('获取缓存失败:', error)
return null
}
}
// 删除缓存
async del(key) {
const cacheKey = this._generateKey(key)
try {
await this.db.where({
cacheKey
}).remove()
return true
} catch (error) {
console.error('删除缓存失败:', error)
return true
}
}
// 批量删除缓存(支持通配符)
async batchDelete(pattern) {
const regExp = new RegExp(`^${this.namespace}:${pattern.replace('*', '.*')}$`)
try {
await this.db.where({
cacheKey: db.RegExp({
regexp: regExp.source,
options: 'i'
})
}).remove()
return true
} catch (error) {
console.error('批量删除缓存失败:', error)
return true
}
}
// 分布式锁
async withLock(key, callback, ttl = 10) {
const lockKey = `lock:${this._generateKey(key)}`
try {
// 查找是否存在锁
const { data } = await this.db.where({
cacheKey: lockKey
}).get()
if (data && data.length > 0) {
const lock = data[0]
// 如果锁已过期,删除锁
if (new Date(lock.expireAt) < new Date()) {
await this.db.where({
cacheKey: lockKey
}).remove()
} else {
throw new BusinessError('资源正在被其他进程使用')
}
}
// 创建锁
await this.db.add({
data: {
cacheKey: lockKey,
expireAt: new Date(Date.now() + ttl * 1000),
createTime: db.serverDate()
}
})
// 执行回调
const value = await callback()
// 释放锁
await this.db.where({
cacheKey: lockKey
}).remove()
return value
} catch (error) {
if (error.message === '资源正在被其他进程使用') {
throw error
}
console.error('锁操作失败:', error)
throw new BusinessError('获取锁失败')
}
}
}
module.exports = Cache