FreeSql icon indicating copy to clipboard operation
FreeSql copied to clipboard

工作单元模式(IUnitOfWork、UnitOfWorkMananger)增加异步处理的api接口

Open ROMYIM opened this issue 1 year ago • 3 comments

工作单元模式的和AOP事件处理添加异步API处理接口

IUnitOfWorkAsync

public interface IAsyncUnitOfWork : IUnitOfWork, IAsyncDisposable
{
    ValueTask<DbTransaction> GetOrBeginTransactionAsync(bool isCreate = true, CancellationToken cancellationToken = default);

    ValueTask CommitAsync(CancellationToken cancellationToken = default);

    ValueTask RollbackAsync(CancellationToken cancellationToken = default);
}

DbContextOptions

public class DbContextOptions
{
    public Func<List<DbContext.EntityChangeReport.ChangeInfo>, ValueTask> OnEntityChangeAsync { get; set; }
    
    public Func<DbContextAuditValueEventArgs, ValueTask> AuditAsync { get; set; }
}

原因

针对freeSql AOP事件或者实体变更事件会有涉及到一些远程调用或者消息发布等操作。其中会涉及到IO操作,希望扩展支持async/await操作

使用场景

实体变更事件-触发发送MQ

  • 领域事件
  • 流程事件触发
  • 分布式事务-事务最终一致性

SQL性能监测监控等

ROMYIM avatar May 28 '24 06:05 ROMYIM

不建议在事务内使用与业务无关的异步,原因是会拖长事务的占用时间,从而导致数据库的锁释放延迟。

异步可能会占用很长的等待时间,不仅仅是IO响应,在应用程序处理量过高的情况下,现在是忙不过来,也会一直排队。

2881099 avatar May 28 '24 09:05 2881099

举个例子,比如在事务内发送http请求,是完全没有必要的,MQ事件可以在事务提交完成之后再处理。

2881099 avatar May 28 '24 09:05 2881099

查看完UnitOfWork的源码,得知UnitOfWorkCommit是先提交事务,在执行事件的。那么事件的执行应该不影响事务的提交。比如下面代码:

public async ValueTask CommitAsync()
        {
            var isCommited = false;
            try
            {
                if (_tran != null)
                {
                    if (_tran.Connection != null) await _tran.CommitAsync();
                    isCommited = true;
                    _fsql?.Aop.TraceAfterHandler?.Invoke(this, new Aop.TraceAfterEventArgs(_tranBefore, "提交", null));

                    if (EntityChangeReport != null && EntityChangeReport.OnEntityChangeAsync != null && EntityChangeReport.Report.Any() == true)
                        await EntityChangeReport.OnEntityChangeAsync(EntityChangeReport.Report);
                }
            }
            catch (Exception ex)
            {
                if (isCommited == false)
                    _fsql?.Aop.TraceAfterHandler?.Invoke(this, new Aop.TraceAfterEventArgs(_tranBefore, "提交失败", ex));
                throw ex;
            }
            finally
            {
                ReturnObject();
                _tranBefore = null;
            }
        }
        public async ValueTask RollbackAsync()
        {
            var isRollbacked = false;
            try
            {
                if (_tran != null)
                {
                    if (_tran.Connection != null) await _tran.RollbackAsync();
                    isRollbacked = true;
                    _fsql?.Aop.TraceAfterHandler?.Invoke(this, new Aop.TraceAfterEventArgs(_tranBefore, "回滚", null));
                }
            }
            catch (Exception ex)
            {
                if (isRollbacked == false)
                    _fsql?.Aop.TraceAfterHandler?.Invoke(this, new Aop.TraceAfterEventArgs(_tranBefore, "回滚失败", ex));
                throw ex;
            }
            finally
            {
                ReturnObject();
                _tranBefore = null;
            }
        }

ROMYIM avatar May 28 '24 10:05 ROMYIM