You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.Net NCo 3.0 tRFC重试机制及幂等性实现方案咨询

.Net NCo 3.0 tRFC 可靠重试机制实现方案

核心设计原则

tRFC的幂等性完全依赖事务ID(TID)实现,SAP系统会保证同一个TID最多执行一次,整套重试机制围绕TID的全生命周期状态管理实现,确保无重复执行、无数据丢失。

首先需要扩展你的TidStatus枚举,覆盖全生命周期状态:

public enum TidStatus
{
    Created, // 事务已创建,未提交
    Submitted, // 已向SAP发起提交请求,未收到明确结果
    Committed, // SAP已确认执行成功
    RolledBack, // 已明确执行失败,无需重试
    MaxRetryFailed // 超过最大重试次数,需人工介入
}

重试触发时机

  • 应用程序启动时,全量扫描数据库中所有非最终状态(Created、Submitted)的TID记录,触发批量重试
  • 配置定时轮询任务(建议间隔10~15分钟),扫描所有提交超过30分钟仍未到最终状态的TID记录
  • 捕获到SAP通信类异常(如RFC_COMMUNICATION_FAILURE、系统宕机、网络超时)时,不直接标记为失败,更新为Submitted状态留待重试

关键实现逻辑

1. 原提交逻辑优化

你原有代码的异常处理逻辑未区分异常类型,且依赖本地文件存储事务数据可靠性低,优化后代码如下:

private void SubmitTransaction(RfcTransaction trans, TidStore tidStore, String data)
{
    try
    {
        // 先将TID状态更新为已提交,避免异常丢失提交记录
        tidStore.SetStatus(trans.Tid.TID, TidStatus.Submitted, null);
        
        IRfcTable dataTable = stfc_write_to_tcpic.GetTable("TCPICDAT");
        dataTable.Append();
        dataTable.SetValue(0, data);
        trans.AddFunction(stfc_write_to_tcpic);
        
        stfc_write_to_tcpic = (IRfcFunction)stfc_write_to_tcpic.Clone();
        dataTable = stfc_write_to_tcpic.GetTable("TCPICDAT");
        dataTable.SetValue(0, data + " -- data of the second function module");
        trans.AddFunction(stfc_write_to_tcpic);
        
        trans.Commit(_ECCsystem);
        tidStore.SetStatus(trans.Tid.TID, TidStatus.Committed, null);

        // 所有本地清理逻辑执行完成后再确认TID,避免本地记录未清理导致重复执行
        _ECCsystem.ConfirmTransactionID(trans.Tid);
        tidStore.DeleteEntry(trans.Tid.TID);
    }
    catch (RfcCommunicationException commEx)
    {
        // 通信类异常,无法确认SAP执行结果,保留Submitted状态等待重试
        tidStore.IncreaseRetryCount(trans.Tid.TID);
        tidStore.SetStatus(trans.Tid.TID, TidStatus.Submitted, commEx.Message);
    }
    catch (RfcAbapException abapEx)
    {
        // ABAP层明确返回执行失败,标记为回滚
        tidStore.SetStatus(trans.Tid.TID, TidStatus.RolledBack, abapEx.Message);
    }
    catch (Exception ex)
    {
        // 其他本地异常,可根据业务场景判断是否需要重试
        tidStore.SetStatus(trans.Tid.TID, TidStatus.RolledBack, ex.Message);
    }
}

2. 重试逻辑实现

重试前必须先校验TID在SAP端的状态,避免重复提交:

// 单次最大重试次数,可根据业务场景调整
private const int MaxRetryCount = 5;

public void RetryPendingTransactions(TidStore tidStore)
{
    var pendingTids = tidStore.GetPendingTids(); // 从数据库获取所有Created、Submitted状态的TID
    foreach (var tidEntry in pendingTids)
    {
        // 加分布式锁/行级锁,避免多实例同时处理同一个TID
        if (!tidStore.TryLockTid(tidEntry.Tid)) continue;
        
        try
        {
            if (tidEntry.RetryCount >= MaxRetryCount)
            {
                tidStore.SetStatus(tidEntry.Tid, TidStatus.MaxRetryFailed, "超过最大重试次数");
                // 触发告警通知人工处理
                continue;
            }
            
            // 先查询SAP端TID状态
            var tid = new RfcTransactionID(tidEntry.Tid);
            var sapTidStatus = RfcTransactionManager.CheckTransactionID(_ECCsystem, tid);
            
            switch (sapTidStatus)
            {
                case RfcTidStatus.Executed:
                    // SAP已执行成功,走本地成功逻辑
                    tidStore.SetStatus(tidEntry.Tid, TidStatus.Committed, null);
                    _ECCsystem.ConfirmTransactionID(tid);
                    tidStore.DeleteEntry(tidEntry.Tid);
                    break;
                case RfcTidStatus.NotFound:
                    // SAP未收到该TID的请求,重新提交
                    var trans = RebuildTransactionFromTidEntry(tidEntry); // 从数据库存储的参数重建RfcTransaction
                    SubmitTransaction(trans, tidStore, tidEntry.Data);
                    break;
                case RfcTidStatus.InProcess:
                    // SAP仍在处理,跳过本次重试
                    break;
            }
        }
        catch (Exception ex)
        {
            // 重试异常,更新重试次数,等待下一轮
            tidStore.IncreaseRetryCount(tidEntry.Tid);
        }
        finally
        {
            tidStore.UnlockTid(tidEntry.Tid);
        }
    }
}

注意事项

  • 所有事务参数必须和TID绑定持久化到数据库,不要存储在本地文件,避免实例宕机、磁盘损坏导致数据丢失
  • 重试时必须复用原有TID,不要生成新的TID,否则会破坏幂等性导致重复执行
  • 多实例部署场景必须加分布式锁,避免同一个TID被多个实例同时处理

内容的提问来源于stack exchange,提问作者Mysterious288

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 08:54:02