diff --git a/Framework/YLErp.Core/DBModels/PushStatus.cs b/Framework/YLErp.Core/DBModels/PushStatus.cs new file mode 100644 index 00000000..547fd6cf --- /dev/null +++ b/Framework/YLErp.Core/DBModels/PushStatus.cs @@ -0,0 +1,50 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace YLErp.DBModels +{ + public enum PushStateEnum + { + 待推送 = 0, + 成功 = 1, + 失败 = 2 + } + + /// + /// 外发推送失败状态。只记录定位信息,不保存报文。 + /// + [Table("push_status")] + public class PushStatus + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public long id { get; set; } + + [Column("value_date")] + public DateTime ValueDate { get; set; } + + [Column("push_type")] + public int PushType { get; set; } + + [Column("record_id")] + public long RecordId { get; set; } + + [Column("state")] + public PushStateEnum State { get; set; } + + [Column("retry_count")] + public int RetryCount { get; set; } + + [Column("last_error")] + public string LastError { get; set; } + + [Column("push_time")] + public DateTime? PushTime { get; set; } + + [Column("create_time")] + public DateTime CreateTime { get; set; } + + [Column("update_time")] + public DateTime? UpdateTime { get; set; } + } +} diff --git a/UnitTestProject/Modules/EodModule/TrsContractKafkaPushServiceTest.cs b/UnitTestProject/Modules/EodModule/TrsContractKafkaPushServiceTest.cs new file mode 100644 index 00000000..88ffb133 --- /dev/null +++ b/UnitTestProject/Modules/EodModule/TrsContractKafkaPushServiceTest.cs @@ -0,0 +1,210 @@ +using YLErp.Abstract; +using YLErp.Helpers; +using YLErp.Modules.EodModule; + +namespace YLErp.Modules.EodModuleTests +{ + [TestClass] + public class TrsContractKafkaPushServiceTest + { + [TestMethod] + public void Push_空日快照_发送一条空消息并使用业务日期作为Key() + { + var valueDate = new DateTime(2026, 8, 24); + var producer = new RecordingKafkaProducer(); + var service = CreateService(producer, valueDate); + + service.Push(valueDate); + + Assert.AreEqual(1, producer.Messages.Count); + Assert.AreEqual("onederiv.trs.contract.v1", producer.Messages[0].Topic); + Assert.AreEqual("2026-08-24", producer.Messages[0].Key); + var payload = JsonHelper.Deserialize(producer.Messages[0].Message); + Assert.AreEqual("2026-08-24", payload.ValueDate); + Assert.AreEqual(0, payload.ContractCount); + Assert.AreEqual(0, payload.Contracts.Count); + } + + [TestMethod] + public void Push_区间内每天分别调用_每个日期各发送一条快照() + { + var valueDates = new[] + { + new DateTime(2026, 8, 20), + new DateTime(2026, 8, 21), + new DateTime(2026, 8, 24) + }; + var producer = new RecordingKafkaProducer(); + var service = new TestableTrsContractKafkaPushService(producer, valueDates.ToDictionary(x => x, CreateEmptySnapshot)); + + foreach (var valueDate in valueDates) + { + service.Push(valueDate); + } + + CollectionAssert.AreEqual( + new[] { "2026-08-20", "2026-08-21", "2026-08-24" }, + producer.Messages.Select(x => x.Key).ToArray()); + CollectionAssert.AreEqual( + new[] { "2026-08-20", "2026-08-21", "2026-08-24" }, + producer.Messages.Select(x => JsonHelper.Deserialize(x.Message).ValueDate).ToArray()); + } + + [TestMethod] + public void Push_首次失败后成功_停止重试且不记录最终失败() + { + var valueDate = new DateTime(2026, 8, 24); + var producer = new RecordingKafkaProducer { FailuresBeforeSuccess = 1 }; + var service = CreateService(producer, valueDate); + + service.Push(valueDate); + + Assert.AreEqual(2, producer.AttemptCount); + Assert.AreEqual(1, producer.Messages.Count); + Assert.AreEqual(0, service.FailureRecords.Count); + } + + [TestMethod] + public void Push_连续失败三次_记录最终失败和三次尝试() + { + var valueDate = new DateTime(2026, 8, 24); + var producer = new RecordingKafkaProducer { FailuresBeforeSuccess = int.MaxValue }; + var service = CreateService(producer, valueDate); + + service.Push(valueDate); + + Assert.AreEqual(3, producer.AttemptCount); + Assert.AreEqual(0, producer.Messages.Count); + Assert.AreEqual(1, service.FailureRecords.Count); + Assert.AreEqual(valueDate, service.FailureRecords[0].ValueDate); + Assert.AreEqual(3, service.FailureRecords[0].RetryCount); + Assert.IsInstanceOfType(service.FailureRecords[0].Exception, typeof(InvalidOperationException)); + } + + [TestMethod] + public void BuildContract_字段使用日终快照和约定来源() + { + var valueDate = new DateTime(2026, 8, 24); + var eodSwap = new eod_swap + { + id = 10, + ValueDate = valueDate, + SwapTradeId = 7, + SwapTradeNo = "TRS-001", + BookId = 3, + ClientId = 8, + NotionalValue = 1000000m, + dv01 = 12.34m, + InitMarginGain = 100m, + InitMarginLoss = 0m + }; + var trade = new trade + { + id = 7, + UnderlyingCode = "600000.SH", + UnderlyingAssetName = "浦发银行", + UnderlyingInstrumentType = "Stock", + StartDate = new DateTime(2026, 8, 1), + ExerciseDate = new DateTime(2027, 8, 1) + }; + var positions = new List + { + new() { SwapTradeId = 7, PositionId = 101, UnderlyingCode = "600000.SH", PositionType = 1 }, + new() { SwapTradeId = 7, PositionId = 102, InterestMode = (int)InterestModeEnum.固定值, InterestRateDefault = 0.0123m, InterestDirection = 2 } + }; + var swapPositions = new Dictionary + { + [101] = new() { id = 101, category_tag = "互换利率" }, + [102] = new() { id = 102, category_tag = "互换利率" } + }; + + var item = TrsContractKafkaPushService.BuildContract( + eodSwap, + new Dictionary { [7] = trade }, + positions, + swapPositions); + + Assert.AreEqual("2026-08-24", item.TradeDate); + Assert.AreEqual(3, item.BookId); + Assert.AreEqual("TRS-001", item.SwapTradeNo); + Assert.AreEqual(8, item.ClientId); + Assert.AreEqual("600000.SH", item.UnderlyingCode); + Assert.AreEqual("浦发银行", item.UnderlyingName); + Assert.AreEqual("Stock", item.UnderlyingInstrumentType); + Assert.AreEqual(1000000m, item.NotionalValue); + Assert.AreEqual("2026-08-01", item.StartDate); + Assert.AreEqual("2027-08-01", item.MaturityDate); + Assert.AreEqual(12.34m, item.Dv01); + Assert.AreEqual(0.0123m, item.FixedRate); + Assert.AreEqual(2, item.InterestDirection); + Assert.AreEqual(1, item.FloatingDirection); + Assert.AreEqual(100m, item.InitMarginGain); + Assert.AreEqual(0m, item.InitMarginLoss); + } + + private static TestableTrsContractKafkaPushService CreateService(RecordingKafkaProducer producer, DateTime valueDate) + { + return new TestableTrsContractKafkaPushService( + producer, + new Dictionary { [valueDate] = CreateEmptySnapshot(valueDate) }); + } + + private static TrsContractSnapshot CreateEmptySnapshot(DateTime valueDate) + { + return new TrsContractSnapshot + { + SchemaVersion = "v1", + ValueDate = valueDate.ToString("yyyy-MM-dd"), + PushTime = "2026-08-24 12:00:00", + ContractCount = 0, + Contracts = new List() + }; + } + + private sealed class TestableTrsContractKafkaPushService : TrsContractKafkaPushService + { + private readonly IReadOnlyDictionary _snapshots; + + public List<(DateTime ValueDate, int RetryCount, Exception Exception)> FailureRecords { get; } = new(); + + public TestableTrsContractKafkaPushService(IKafkaProduce producer, IReadOnlyDictionary snapshots) + : base(new YLContext(), producer, "onederiv.trs.contract.v1") + { + _snapshots = snapshots; + } + + protected override TrsContractSnapshot BuildSnapshot(DateTime valueDate) + { + return _snapshots[valueDate]; + } + + protected override void RecordFailures(DateTime valueDate, int retryCount, Exception exception) + { + FailureRecords.Add((valueDate, retryCount, exception)); + } + } + + private sealed class RecordingKafkaProducer : IKafkaProduce + { + public int FailuresBeforeSuccess { get; set; } + public int AttemptCount { get; private set; } + public List<(string Topic, string Key, string Message)> Messages { get; } = new(); + + public void Produce(string topic, string message) + { + throw new NotSupportedException(); + } + + public void Produce(string topic, string key, string message) + { + AttemptCount++; + if (AttemptCount <= FailuresBeforeSuccess) + { + throw new InvalidOperationException("Kafka unavailable"); + } + + Messages.Add((topic, key, message)); + } + } + } +} diff --git a/YLErpDAL/Abstract/IKafkaProduce.cs b/YLErpDAL/Abstract/IKafkaProduce.cs index d95e6ddc..a0a78943 100644 --- a/YLErpDAL/Abstract/IKafkaProduce.cs +++ b/YLErpDAL/Abstract/IKafkaProduce.cs @@ -9,5 +9,7 @@ namespace YLErp.Abstract public interface IKafkaProduce { void Produce(string topic, string message); + + void Produce(string topic, string key, string message); } } diff --git a/YLErpDAL/DataBase/YLContext.cs b/YLErpDAL/DataBase/YLContext.cs index dbffc149..1c828a21 100644 --- a/YLErpDAL/DataBase/YLContext.cs +++ b/YLErpDAL/DataBase/YLContext.cs @@ -354,6 +354,7 @@ namespace YLErp.BLL public DbSet eod_swap_position { get; set; } public DbSet swap_event { get; set; } public DbSet eod_swap { get; set; } + public DbSet push_status { get; set; } public DbSet trade_obervation { get; set; } public DbSet SystemLogs { get; set; } diff --git a/YLErpDAL/Helpers/KafkaProduceHelper.cs b/YLErpDAL/Helpers/KafkaProduceHelper.cs index b01955fd..4c5789a3 100644 --- a/YLErpDAL/Helpers/KafkaProduceHelper.cs +++ b/YLErpDAL/Helpers/KafkaProduceHelper.cs @@ -63,19 +63,29 @@ namespace YLErp.Helpers public void Produce(string topic,string message) { - var kafkaMessage = new Message - { - Key=null, - Value = message - }; try { - _producer.ProduceAsync(topic, kafkaMessage).GetAwaiter().GetResult(); + ProduceCore(topic, null, message); } catch (Exception ex) { _logger.Error($"Topic:{topic} send failed",ex); } } + + public void Produce(string topic, string key, string message) + { + ProduceCore(topic, key, message); + } + + private void ProduceCore(string topic, string key, string message) + { + var kafkaMessage = new Message + { + Key = key, + Value = message + }; + _producer.ProduceAsync(topic, kafkaMessage).GetAwaiter().GetResult(); + } } } diff --git a/YLErpDAL/Model/KafkaConfig.cs b/YLErpDAL/Model/KafkaConfig.cs index 341ba482..5cd9cf36 100644 --- a/YLErpDAL/Model/KafkaConfig.cs +++ b/YLErpDAL/Model/KafkaConfig.cs @@ -60,7 +60,7 @@ namespace YLErp.Model /// /// TRS合约数据推送topic(对外,如onebp等) /// - public string ContractTopic { get; set; } = "onederi.trs.onebp.contract.v1"; + public string ContractTopic { get; set; } = "onederiv.trs.contract.v1"; } } diff --git a/YLErpDAL/Modules/EodModule/SettlementModule/EodTaskRunner.cs b/YLErpDAL/Modules/EodModule/SettlementModule/EodTaskRunner.cs index eb3da751..0a9e65fe 100644 --- a/YLErpDAL/Modules/EodModule/SettlementModule/EodTaskRunner.cs +++ b/YLErpDAL/Modules/EodModule/SettlementModule/EodTaskRunner.cs @@ -10,6 +10,12 @@ using YLErp.Modules.SystemModule; using YLErp.Modules.TradeDalModule; using YLErp.Modules.TradeModule.DealModule; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using YieldChain.Commons; +using YLErp.Abstract; +using YLErp.Model; + namespace YLErp.Modules.EodModule.SettlementModule { /// @@ -445,12 +451,35 @@ where {nameof(t.TaskStartTime)}>'{startDateStr}' and {nameof(t.TaskState)}={(int } ClientBalanceUtility.saveClientRiskMonitor(eodTask.ValueDate); new EodFileService(this.OptUser).GenerateFileAfterEod(eodTask.ValueDate); + PushTrsContractSnapshot(eodTask.ValueDate); //执行下一日 eodTask.ValueDate = eodTask.ValueDate.AddDays(1); eodTask.TaskEndTime = DateTime.Now; } } + private void PushTrsContractSnapshot(DateTime valueDate) + { + try + { + var provider = YLServiceLocator.ServiceProvider; + var kafkaProduce = provider?.GetService(); + var kafkaOptions = provider?.GetService>(); + if (kafkaProduce == null || kafkaOptions?.Value == null) + { + LogFactory.GetLogger("TRS合约日终Kafka推送").Error("Kafka service or configuration is unavailable"); + return; + } + + using var pushDbContext = DbContextFactory.GetYLDbContext(); + new TrsContractKafkaPushService(pushDbContext, kafkaProduce, kafkaOptions.Value.ContractTopic).Push(valueDate); + } + catch (Exception ex) + { + LogFactory.GetLogger("TRS合约日终Kafka推送").Error($"TRS contract snapshot task failed, valueDate:{valueDate:yyyy-MM-dd}", ex); + } + } + /// /// 查找第一个可用的任务 /// diff --git a/YLErpDAL/Modules/EodModule/TrsContractKafkaPushService.cs b/YLErpDAL/Modules/EodModule/TrsContractKafkaPushService.cs new file mode 100644 index 00000000..0efc85e1 --- /dev/null +++ b/YLErpDAL/Modules/EodModule/TrsContractKafkaPushService.cs @@ -0,0 +1,233 @@ +using YLErp.Abstract; +using YLErp.BLL; +using YLErp.DBModels; +using YLErp.Helpers; + +namespace YLErp.Modules.EodModule +{ + /// + /// 收盘后按交易日推送 TRS 合约全量快照。 + /// + public class TrsContractKafkaPushService + { + private const string DateFormat = "yyyy-MM-dd"; + private const string DateTimeFormat = "yyyy-MM-dd HH:mm:ss"; + private const string InterestCategory = "互换利率"; + private const int TrsContractPushType = 1; + private const int MaxAttempts = 3; + + private readonly YLContext _dbContext; + private readonly IKafkaProduce _kafkaProduce; + private readonly string _topic; + private readonly IYcLogger _logger; + + public TrsContractKafkaPushService(YLContext dbContext, IKafkaProduce kafkaProduce, string topic) + { + _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); + _kafkaProduce = kafkaProduce ?? throw new ArgumentNullException(nameof(kafkaProduce)); + _topic = string.IsNullOrWhiteSpace(topic) ? throw new ArgumentException("Kafka topic is empty", nameof(topic)) : topic; + _logger = LogFactory.GetLogger(nameof(TrsContractKafkaPushService)); + } + + public void Push(DateTime valueDate) + { + valueDate = valueDate.Date; + + TrsContractSnapshot snapshot; + string payload; + try + { + snapshot = BuildSnapshot(valueDate); + payload = JsonHelper.Serialize(snapshot, true, true); + } + catch (Exception ex) + { + _logger.Error($"TRS contract snapshot build failed, valueDate:{valueDate:yyyy-MM-dd}", ex); + RecordFailures(valueDate, 0, ex); + return; + } + + var key = valueDate.ToString(DateFormat); + Exception lastException = null; + for (var attempt = 1; attempt <= MaxAttempts; attempt++) + { + try + { + _kafkaProduce.Produce(_topic, key, payload); + _logger.Info($"TRS contract snapshot sent, valueDate:{key}, topic:{_topic}, count:{snapshot.ContractCount}, attempt:{attempt}"); + return; + } + catch (Exception ex) + { + lastException = ex; + _logger.Error($"TRS contract snapshot send failed, valueDate:{key}, topic:{_topic}, attempt:{attempt}", ex); + } + } + + _logger.Error($"TRS contract snapshot send exhausted retries, valueDate:{key}, topic:{_topic}, attempts:{MaxAttempts}"); + RecordFailures(valueDate, MaxAttempts, lastException); + } + + protected virtual void RecordFailures(DateTime valueDate, int retryCount, Exception exception) + { + try + { + var recordIds = _dbContext.eod_swap + .Where(x => x.ValueDate == valueDate) + .Select(x => x.id) + .ToList(); + if (recordIds.Count == 0) + { + recordIds.Add(0); + } + + var now = DateTime.Now; + var statuses = _dbContext.push_status + .Where(x => x.ValueDate == valueDate + && x.PushType == TrsContractPushType + && recordIds.Contains(x.RecordId)) + .ToList(); + var error = exception?.ToString(); + if (error?.Length > 2000) + { + error = error.Substring(0, 2000); + } + + foreach (var recordId in recordIds) + { + var status = statuses.FirstOrDefault(x => x.RecordId == recordId); + if (status == null) + { + status = new PushStatus + { + ValueDate = valueDate, + PushType = TrsContractPushType, + RecordId = recordId, + CreateTime = now + }; + _dbContext.push_status.Add(status); + } + + status.State = PushStateEnum.失败; + status.RetryCount = retryCount; + status.LastError = error; + status.PushTime = now; + status.UpdateTime = now; + } + + _dbContext.SaveChanges(); + } + catch (Exception ex) + { + _logger.Error($"TRS contract push failure status save failed, valueDate:{valueDate:yyyy-MM-dd}", ex); + } + } + + protected virtual TrsContractSnapshot BuildSnapshot(DateTime valueDate) + { + var eodSwaps = _dbContext.eod_swap + .Where(x => x.ValueDate == valueDate) + .AsNoTracking() + .ToList(); + var tradeIds = eodSwaps.Select(x => x.SwapTradeId).Distinct().ToList(); + var trades = _dbContext.trade + .Where(x => tradeIds.Contains(x.id)) + .AsNoTracking() + .ToDictionary(x => x.id); + var eodPositions = _dbContext.eod_swap_position + .Where(x => x.ValueDate == valueDate && tradeIds.Contains(x.SwapTradeId) && !x.Invalid) + .AsNoTracking() + .ToList(); + var positionIds = eodPositions.Select(x => x.PositionId).Distinct().ToList(); + var swapPositions = _dbContext.swap_position + .Where(x => positionIds.Contains(x.id) && !x.Invalid && x.category_tag == InterestCategory) + .AsNoTracking() + .ToDictionary(x => x.id); + + var contracts = eodSwaps.Select(eodSwap => BuildContract(eodSwap, trades, eodPositions, swapPositions)).ToList(); + return new TrsContractSnapshot + { + SchemaVersion = "v1", + ValueDate = valueDate.ToString(DateFormat), + PushTime = DateTime.Now.ToString(DateTimeFormat), + ContractCount = contracts.Count, + Contracts = contracts + }; + } + + internal static TrsContractSnapshotItem BuildContract( + eod_swap eodSwap, + IReadOnlyDictionary trades, + IReadOnlyCollection eodPositions, + IReadOnlyDictionary swapPositions) + { + if (!trades.TryGetValue(eodSwap.SwapTradeId, out var trade)) + { + throw new InvalidOperationException($"TRS trade not found, swapTradeId:{eodSwap.SwapTradeId}"); + } + + var positions = eodPositions.Where(x => x.SwapTradeId == eodSwap.SwapTradeId).ToList(); + var floating = positions.Where(x => !string.IsNullOrWhiteSpace(x.UnderlyingCode) && swapPositions.ContainsKey(x.PositionId)).ToList(); + var interest = positions.Where(x => string.IsNullOrWhiteSpace(x.UnderlyingCode) + && ConsTrade.InterestModels.Contains(x.InterestMode) + && swapPositions.TryGetValue(x.PositionId, out var swapPosition) + && swapPosition.category_tag == InterestCategory).ToList(); + + if (floating.Count != 1 || interest.Count != 1) + { + throw new InvalidOperationException($"TRS legs invalid, swapTradeId:{eodSwap.SwapTradeId}, floating:{floating.Count}, interest:{interest.Count}"); + } + + var interestLeg = interest[0]; + var floatingLeg = floating[0]; + return new TrsContractSnapshotItem + { + TradeDate = eodSwap.ValueDate.ToString(DateFormat), + BookId = eodSwap.BookId, + SwapTradeNo = eodSwap.SwapTradeNo, + ClientId = eodSwap.ClientId, + UnderlyingCode = trade.UnderlyingCode, + UnderlyingName = trade.UnderlyingAssetName, + UnderlyingInstrumentType = trade.UnderlyingInstrumentType, + NotionalValue = eodSwap.NotionalValue, + Dv01 = eodSwap.dv01 ?? 0, + StartDate = trade.StartDate?.ToString(DateFormat), + MaturityDate = trade.ExerciseDate?.ToString(DateFormat), + FixedRate = interestLeg.InterestRateDefault, + InterestDirection = interestLeg.InterestDirection, + FloatingDirection = floatingLeg.PositionType, + InitMarginGain = eodSwap.InitMarginGain, + InitMarginLoss = eodSwap.InitMarginLoss + }; + } + } + + public class TrsContractSnapshot + { + public string SchemaVersion { get; set; } + public string ValueDate { get; set; } + public string PushTime { get; set; } + public int ContractCount { get; set; } + public List Contracts { get; set; } + } + + public class TrsContractSnapshotItem + { + public string TradeDate { get; set; } + public int BookId { get; set; } + public string SwapTradeNo { get; set; } + public int ClientId { get; set; } + public string UnderlyingCode { get; set; } + public string UnderlyingName { get; set; } + public string UnderlyingInstrumentType { get; set; } + public decimal NotionalValue { get; set; } + public decimal Dv01 { get; set; } + public string StartDate { get; set; } + public string MaturityDate { get; set; } + public decimal FixedRate { get; set; } + public int InterestDirection { get; set; } + public int FloatingDirection { get; set; } + public decimal InitMarginGain { get; set; } + public decimal InitMarginLoss { get; set; } + } +} diff --git a/YLErpWeb/appsettings.dev.json b/YLErpWeb/appsettings.dev.json index ecceba98..3e268d15 100644 --- a/YLErpWeb/appsettings.dev.json +++ b/YLErpWeb/appsettings.dev.json @@ -34,6 +34,7 @@ "CompressionType": 0, // 消息压缩方式,可以是 None(0)、Gzip(1)、Snappy(2)、Lz4(3)、Zstd(4) 中的一种, "MessageTimeoutMs": 3000, // 控制生产者等待消息确认的时间,单位是毫秒 "ClientRateTopic": "ylClientRateTopic", //客户互换费率生产topic + "ContractTopic": "onederiv.trs.contract.v1", //TRS合约日终推送topic "HedgingAccountTopic": "ylHedgingAccountTopic", //对冲账户生产topic "ReqAccountCapitalTopic": "ReqAccountCapital", //账户资金请求topic "OnRspAccountCapitalTopic": "OnRspAccountCapital", //账户资金请求返回topic diff --git a/YLErpWeb/appsettings.local.json b/YLErpWeb/appsettings.local.json index a42f229b..e2956912 100644 --- a/YLErpWeb/appsettings.local.json +++ b/YLErpWeb/appsettings.local.json @@ -34,6 +34,7 @@ "CompressionType": 0, // 消息压缩方式,可以是 None(0)、Gzip(1)、Snappy(2)、Lz4(3)、Zstd(4) 中的一种, "MessageTimeoutMs": 3000, // 控制生产者等待消息确认的时间,单位是毫秒 "ClientRateTopic": "ylClientRateTopic", //客户互换费率生产topic + "ContractTopic": "onederiv.trs.contract.v1", //TRS合约日终推送topic "HedgingAccountTopic": "ylHedgingAccountTopic", //对冲账户生产topic "ReqAccountCapitalTopic": "ReqAccountCapital", //账户资金请求topic "OnRspAccountCapitalTopic": "OnRspAccountCapital", //账户资金请求返回topic diff --git a/YLErpWeb/appsettings.prod.json b/YLErpWeb/appsettings.prod.json index 3df07b7a..a7264a53 100644 --- a/YLErpWeb/appsettings.prod.json +++ b/YLErpWeb/appsettings.prod.json @@ -36,6 +36,7 @@ "CompressionType": 0, // 消息压缩方式,可以是 None(0)、Gzip(1)、Snappy(2)、Lz4(3)、Zstd(4) 中的一种, "MessageTimeoutMs": 3000, // 控制生产者等待消息确认的时间,单位是毫秒 "ClientRateTopic": "ylClientRateTopic", //客户互换费率生产topic + "ContractTopic": "onederiv.trs.contract.v1", //TRS合约日终推送topic "HedgingAccountTopic": "ylHedgingAccountTopic", //对冲账户生产topic "AccountCapitalTopicGroupId": "YiLian_OnRspAccountCapitalConsumer", //账户资金消费组 "ReqAccountCapitalTopic": "ReqAccountCapital", //账户资金请求topic diff --git a/YLErpWeb/appsettings.uat.json b/YLErpWeb/appsettings.uat.json index 87232cdd..fb6d933c 100644 --- a/YLErpWeb/appsettings.uat.json +++ b/YLErpWeb/appsettings.uat.json @@ -36,6 +36,7 @@ "CompressionType": 0, // 消息压缩方式,可以是 None(0)、Gzip(1)、Snappy(2)、Lz4(3)、Zstd(4) 中的一种, "MessageTimeoutMs": 3000, // 控制生产者等待消息确认的时间,单位是毫秒 "ClientRateTopic": "ylClientRateTopic", //客户互换费率生产topic + "ContractTopic": "onederiv.trs.contract.v1", //TRS合约日终推送topic "HedgingAccountTopic": "ylHedgingAccountTopic", //对冲账户生产topic "AccountCapitalTopicGroupId": "YiLian_OnRspAccountCapitalConsumer", //账户资金消费组 "ReqAccountCapitalTopic": "ReqAccountCapital", //账户资金请求topic