feat: 修改项目后自动删除项目工作区相关目录
This commit is contained in:
@ -1,8 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { PasswordConverter } from './services/password-converter';
|
||||
import { RedisMutexModule } from './redis-mutex/redis-mutex.module';
|
||||
|
||||
@Module({
|
||||
providers: [PasswordConverter],
|
||||
exports: [PasswordConverter],
|
||||
exports: [PasswordConverter, RedisMutexModule],
|
||||
imports: [RedisMutexModule],
|
||||
})
|
||||
export class CommonsModule {}
|
||||
|
10
src/commons/redis-mutex/redis-mutex.module.ts
Normal file
10
src/commons/redis-mutex/redis-mutex.module.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { RedisMutexService } from './redis-mutex.service';
|
||||
import { RedisModule } from 'nestjs-redis';
|
||||
|
||||
@Module({
|
||||
imports: [RedisModule],
|
||||
providers: [RedisMutexService],
|
||||
exports: [RedisMutexService],
|
||||
})
|
||||
export class RedisMutexModule {}
|
18
src/commons/redis-mutex/redis-mutex.service.spec.ts
Normal file
18
src/commons/redis-mutex/redis-mutex.service.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { RedisMutexService } from './redis-mutex.service';
|
||||
|
||||
describe('RedisMutexService', () => {
|
||||
let service: RedisMutexService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [RedisMutexService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<RedisMutexService>(RedisMutexService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
71
src/commons/redis-mutex/redis-mutex.service.ts
Normal file
71
src/commons/redis-mutex/redis-mutex.service.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { RedisService } from 'nestjs-redis';
|
||||
import * as uuid from 'uuid';
|
||||
import { ApplicationException } from '../exceptions/application.exception';
|
||||
|
||||
export interface RedisMutexOption {
|
||||
/**
|
||||
* seconds
|
||||
*/
|
||||
expires?: number;
|
||||
/**
|
||||
* seconds
|
||||
*/
|
||||
timeout?: number | null;
|
||||
/**
|
||||
* milliseconds
|
||||
*/
|
||||
retryDelay?: number;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class RedisMutexService {
|
||||
constructor(private readonly redisClient: RedisService) {}
|
||||
|
||||
public async lock(
|
||||
key: string,
|
||||
{ expires = 100, timeout = 10, retryDelay = 100 }: RedisMutexOption = {
|
||||
expires: 100,
|
||||
timeout: 10,
|
||||
retryDelay: 100,
|
||||
},
|
||||
) {
|
||||
const redisKey = `${'mutex-lock'}:${key}`;
|
||||
const redis = this.redisClient.getClient();
|
||||
const value = uuid.v4();
|
||||
const timeoutAt = timeout ? Date.now() + timeout * 1000 : null;
|
||||
|
||||
while (
|
||||
!(await redis
|
||||
.set(redisKey, value, 'EX', expires, 'NX')
|
||||
.then(() => true)
|
||||
.catch(() => false))
|
||||
) {
|
||||
if (timeoutAt && timeoutAt > Date.now()) {
|
||||
throw new ApplicationException('lock timeout');
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
||||
}
|
||||
|
||||
const renewTimer = setInterval(() => {
|
||||
redis.expire(redisKey, expires);
|
||||
}, (expires * 1000) / 2);
|
||||
|
||||
return async () => {
|
||||
clearInterval(renewTimer);
|
||||
await redis.eval(
|
||||
`
|
||||
if redis.call("get", KEYS[1]) == ARGV[1]
|
||||
then
|
||||
return redis.call("del", KEYS[1])
|
||||
else
|
||||
return 0
|
||||
end
|
||||
`,
|
||||
1,
|
||||
redisKey,
|
||||
value,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user