-
|
I'm loving @nestjs-cls/transactional, great work! When using transactional, how can I perform logic once a Transaction is committed. For example, create a record in the database and then insert its id/value into redis. If the transaction fails for whatever reason, then that is bad data. Make we could have something like this :) |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
|
Thanks for the suggestion, but adding more features to the Transactional plugin beside propagating the transaction object is a non-goal. The transaction is committed when the method decorated with a Option 1The easiest userland solution is just to call it explicitly after a async someAction(input: Input): Promise<Output> {
await this.someActionTransaction()
.then((value) => this.updateState(value))
}
@Transactional()
async someActionTransaction(input: Input): Promise<Output> { /* ... */}Option 2Another options is to use async someAction(input: Input): Promise<Output> {
await this.txHost.withTransaction(() => { /* ... */ })
.then((value) => this.updateState(value))
}Option 3If you want to abstract it away, you could even create a custom decorator that wraps over the function and calls finishers when the function returns or throws. export function WithFinishers<TResult>(
onSuccess: (result: TResult) => void | Promise<void>,
onError: (error: any) => void | Promise<void>,
) {
return (
_target: any,
_propertyKey: string | symbol,
descriptor: TypedPropertyDescriptor<
(...args: any[]) => Promise<TResult>
>,
) => {
const original = descriptor.value;
if (typeof original !== 'function') {
throw new Error('WithFinishers can only be used on functions.');
}
descriptor.value = async function (...args: any[]) {
try {
const result = await original.apply(this, args);
await onSuccess.call(this, result);
return result;
} catch (error) {
await onError.call(this, error);
throw error;
}
};
};
}
// and then use it like so
// (note that the order of decorators matter in this case. The outermost wraps over the innermost)
@WithFinishers((this, value) => this.updateState(value))
@Transactional()
async function someAction(input: Input): Promise<Output> { /*... */}Option 4You could even go as far as to wrap the @TransactionalWithFinishers((this, value) => this.updateState(value))
async function someAction(input: Input): Promise<Output> { /*... */}It is important to note that the finishers should always run outside of the transaction. There is no technical limitation that prevents this feature from being implemented in the userland, and therefore I won't be considering adding it to the library at this time. |
Beta Was this translation helpful? Give feedback.
Thanks for the suggestion, but adding more features to the Transactional plugin beside propagating the transaction object is a non-goal.
The transaction is committed when the method decorated with a
@Transactionalreturns successfully, you can then call whatever functions you want.Option 1
The easiest userland solution is just to call it explicitly after a
@Transactional-decorated method endsOption 2
Another options is to use
TransactionHost#withTransaction