Transactional Decorator
Decorator
decorator는 함수를 반환하는 표현식으로
class, method, property에 @로 시작하는 decorator를 붙여서 코드를 수정하거나 추가해 주는 문법이다.
이를 통해 횡단 관심사를 분리해서 관점 지향 프로그래밍을 할 수 있다.
트랜잭션 로직이 필요한 메서드에 아래와 같은 decorator를 만들어서 적용할 수 있다.
descriptor.value는 원본 함수이고 트랜잭션 로직으로 감싸서 바꿔치기 한걸 볼 수 있다.
export function Transactional() {
return function (
target: any,
propertyKey: string,
descriptor: PropertyDescriptor,
) {
const original = descriptor.value;
descriptor.value = async function (...args: any[]) {
return this.prisma.$transaction(async (tx) => {
return await original.apply(this, args);
});
};
};
}
AsyncLocalStroage
async_hooks은 비동기 리소스의 실행 흐름을 추적할 수 있는 API이다.
비동기 리소스마다 고유한 asyncId를 가지고 있고 아래와 같은 hook을 제공한다.
init은 비동기 리소스 생성 시 호출되고
before와 after는 callback 실행 전과 후에 호출되고
destory는 비동기 리소스 소멸 시 호출된다.
const hook = async_hooks.createHook({
init(asyncId, type, triggerAsyncId) {
},
before(asyncId) {
},
after(asyncId) {
},
destroy(asyncId) {
},
});
hook.enable();
AsyncLocalStorage는 async_hooks을 기반으로 비동기 context별로 데이터를 저장하고 관리할 수 있는 API이다.
이를 사용하면 함수마다 context를 매개변수로 전달하지 않고도 context를 참조할 수 있다.
AsyncLocalStorage의 run 메서드에서 데이터를 바인딩하면
callback 함수에서 getStore 메서드를 통해서 해당 데이터를 참조할 수 있다.
asyncLocalStorage.run(store, async () => {
})
asyncLocalStorage.getStore();
트랜잭션 전파기능을 구현하면서
asyncLocalStorage를 조회해서 기존 트랜잭션이 있으면 해당 트랜잭션을 사용하고
없으면 새로운 트랜잭션을 생성하도록 했다.
const asyncLocalStorage = new AsyncLocalStorage<Prisma.TransactionClient>();
export function Transactional() {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const original = descriptor.value;
descriptor.value = async function (...args: any[]) {
const existingTx = asyncLocalStorage.getStore();
if (existingTx) {
return await original.apply(this, args);
}
return this.prisma.$transaction(async (tx) => {
return asyncLocalStorage.run(tx, async () => {
return await original.apply(this, args);
});
});
};
};
}
'프로젝트 > XRP 환전 서비스' 카테고리의 다른 글
| [일관성 보장] Outbox Pattern을 적용해보자 (0) | 2025.10.03 |
|---|