EasilyNET.RabbitBus.AspNetCore 4.25.905.150

dotnet add package EasilyNET.RabbitBus.AspNetCore --version 4.25.905.150
                    
NuGet\Install-Package EasilyNET.RabbitBus.AspNetCore -Version 4.25.905.150
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="EasilyNET.RabbitBus.AspNetCore" Version="4.25.905.150" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EasilyNET.RabbitBus.AspNetCore" Version="4.25.905.150" />
                    
Directory.Packages.props
<PackageReference Include="EasilyNET.RabbitBus.AspNetCore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add EasilyNET.RabbitBus.AspNetCore --version 4.25.905.150
                    
#r "nuget: EasilyNET.RabbitBus.AspNetCore, 4.25.905.150"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package EasilyNET.RabbitBus.AspNetCore@4.25.905.150
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=EasilyNET.RabbitBus.AspNetCore&version=4.25.905.150
                    
Install as a Cake Addin
#tool nuget:?package=EasilyNET.RabbitBus.AspNetCore&version=4.25.905.150
                    
Install as a Cake Tool
EasilyNET.RabbitBus.AspNetCore

支持延时队列,服务端需要启用 rabbitmq-delayed-message-exchange 插件

  • 支持同一个消息被多个 Handler 消费
  • 支持忽略指定 Handler 执行
  • 支持事件级 QoS、Headers、交换机/队列参数、优先级队列
  • 支持处理器并发控制或顺序执行,内置重试与超时弹性策略
  • 支持发布确认(Publisher Confirms)确保消息可靠性投递
  • 支持批量发布消息提高吞吐量
  • 现代配置: 使用流畅 API 完成所有配置,无需在事件或处理器上标注特性
如何使用
  • 使用 NuGet 包管理工具添加依赖 EasilyNET.RabbitBus.AspNetCore
  • 等待下载完成和同意开源协议后,即可使用本库.
Step 1. 在 Program.cs 中注册消息总线(现代流式配置)
// Program.cs / Startup
builder.Services.AddRabbitBus(c =>
{
    // 1) 连接配置(支持单点/集群,此处以连接串为例)
    c.WithConnection(f => f.Uri = new(builder.Configuration.GetConnectionString("Rabbit")!));

    // 2) 消费者默认设置
    // ConsumerDispatchConcurrency: 消费者调度并发数,控制同时处理的消息数(默认: 1)
    // PrefetchCount: QoS预取计数,限制未确认消息的数量(默认: 50)
    c.WithConsumerSettings(dispatchConcurrency: 10, prefetchCount: 100);

    // 3) 弹性与发布确认
    // PublisherConfirms: 启用发布确认模式,确保消息可靠投递(默认: false)
    // MaxOutstandingConfirms: 最大未确认发布数量(默认: 1000)
    // BatchSize: 批量发布大小(默认: 100)
    // ConfirmTimeoutMs: 发布确认超时时间(毫秒,默认: 30000)
    c.WithResilience(retryCount: 5, publisherConfirms: true, maxOutstandingConfirms: 1000, batchSize: 100, confirmTimeoutMs: 30000);

    // 4) 应用标识(可选)
    c.WithApplication("YourAppName");

    // 5) 处理器并发控制(全局设置,非顺序执行时生效)
    // HandlerMaxDegreeOfParallelism: 单个事件处理器最大并发度,防止CPU过载(默认: 4)
    c.WithHandlerConcurrency(handlerMaxDegreeOfParallelism: 4);

    // ===== 事件配置 =====
    // 5.1 Routing(直连)示例
    c.AddEvent<TestEvent>(EModel.Routing, exchangeName: "test.exchange", routingKey: "test.key", queueName: "test.queue")
     .WithEventQos(prefetchCount: 20)  // 事件级QoS设置
     .WithEventHeaders(new() { ["x-version"] = "v1" })
     .WithEventQueueArgs(new() { ["x-max-priority"] = 9 }) // 使用优先级需声明此参数
     .WithEventExchangeArgs(new() { ["alternate-exchange"] = "alt.exchange" })
     .ConfigureEvent(ec => ec.SequentialHandlerExecution = false) // 同一消息多个处理器时并行处理
     .And();

    // 5.2 延迟消息示例(需要安装 rabbitmq-delayed-message-exchange 插件)
    c.AddEvent<DelayedMessageEvent>(EModel.Delayed, exchangeName: "delayed.exchange", routingKey: "delayed.key", queueName: "delayed.queue");

    // 5.3 发布/订阅(Fanout)
    c.AddEvent<FanoutEvent>(EModel.PublishSubscribe, "fanout.exchange", queueName: "fanout.queue");

    // 忽略某个处理器(当同一事件存在多个处理器时)
    c.IgnoreHandler<TestEvent, TestEventHandlerSecond>();

    // 如需自定义序列化器
    // c.WithSerializer<MsgPackSerializer>();
});
Step 2. 定义事件与处理器(无需再使用特性)
using EasilyNET.RabbitBus.Core;
using EasilyNET.RabbitBus.Core.Abstraction;

// 事件只需实现 IEvent 或继承 Event,无需 [Exchange]/[Qos]/[IgnoreHandler] 等特性
public class TestEvent : Event
{
    public string Message { get; set; } = default!;
}

public class DelayedMessageEvent : Event
{
    public string Message { get; set; } = default!;
}

public class TestEventHandler(ILogger<TestEventHandler> logger) : IEventHandler<TestEvent>
{
    public Task HandleAsync(TestEvent @event)
    {
        logger.LogInformation("TestEvent: {event} @ {time}", @event.Message, DateTime.Now);
        return Task.CompletedTask;
    }
}

// 仍可定义多个处理器消费同一消息,是否忽略通过配置 c.IgnoreHandler<TEvent, THandler>() 控制
public class TestEventHandlerSecond(ILogger<TestEventHandlerSecond> logger) : IEventHandler<TestEvent>
{
    public Task HandleAsync(TestEvent @event)
    {
        logger.LogInformation("SecondHandler: {event} @ {time}", @event.Message, DateTime.Now);
        return Task.CompletedTask;
    }
}
Step 3. 发布消息
// 构造注入 IBus 后使用
private readonly IBus _bus;

public MyController(IBus bus) => _bus = bus;

[HttpPost("send")]
public async Task Send()
{
    // 普通消息(按事件配置路由)
    await _bus.Publish(new TestEvent { Message = "normal" });

    // 显式指定 routingKey, 适配 Topic/多路由发信场景
    await _bus.Publish(new TestEvent { Message = "topic" }, routingKey: "topic.queue.1");

    // 使用优先级(需为队列设置 x-max-priority)
    await _bus.Publish(new TestEvent { Message = "priority" }, priority: 5);

    // 批量发布消息(提高吞吐量)
    var events = Enumerable.Range(1, 100).Select(i => new TestEvent { Message = $"batch-{i}" });
    await _bus.PublishBatch(events);

    // 批量发布带自定义路由键
    await _bus.PublishBatch(events, routingKey: "batch.topic");

    // 延迟消息(毫秒)
    await _bus.Publish(new DelayedMessageEvent { Message = "delay-5s" }, ttl: 5000);
}
使用自定义序列化器
  • 默认序列化器为 System.Text.Json
  • 若要使用其他序列化器,实现 IBusSerializer 接口并在注册时使用 WithSerializer<T>() 指定
public sealed class MsgPackSerializer : IBusSerializer
{
    private static readonly MessagePackSerializerOptions standardOptions =
        MessagePackSerializerOptions.Standard
            .WithResolver(CompositeResolver.Create(NativeDateTimeResolver.Instance, ContractlessStandardResolver.Instance))
            .WithSecurity(MessagePackSecurity.UntrustedData);

    private static readonly MessagePackSerializerOptions lz4BlockArrayOptions =
        standardOptions.WithCompression(MessagePackCompression.Lz4BlockArray);

    private static readonly MessagePackSerializerOptions lz4BlockOptions =
        standardOptions.WithCompression(MessagePackCompression.Lz4Block);

    public byte[] Serialize(object? obj, Type type)
    {
        var data = MessagePackSerializer.Serialize(type, obj, standardOptions);
        var options = data.Length > 8192 ? lz4BlockArrayOptions : lz4BlockOptions;
        return MessagePackSerializer.Serialize(type, obj, options);
    }

    public object? Deserialize(byte[] data, Type type)
    {
        var options = data.Length > 8192 ? lz4BlockArrayOptions : lz4BlockOptions;
        return MessagePackSerializer.Deserialize(type, data, options);
    }
}

// 注册
builder.Services.AddRabbitBus(c =>
{
    // ...其他配置
    c.WithSerializer<MsgPackSerializer>();
});
注意事项
  • 延迟队列: 必须安装 rabbitmq-delayed-message-exchange 插件; 框架会自动为延迟交换机声明 x-delayed-type=direct
  • 优先级队列: 若使用优先级,请为队列设置参数 x-max-priority
  • 默认交换机: EModel.None 表示不显式声明交换机,使用默认交换机; 此时 routingKey 应为队列名
  • 路由键覆盖: Publish 的 routingKey 参数用于覆盖事件配置中的路由键,便于 Topic 下多路由生产者发信
  • 顺序执行: 可通过 ConfigureEvent(ec ⇒ ec.SequentialHandlerExecution = true) 开启同一事件多个处理器的顺序执行
  • 并发控制: HandlerMaxDegreeOfParallelism 用于控制单个事件处理器的最大并发度,防止 CPU 过载(默认值: 4)
  • 发布确认: PublisherConfirms 启用后会影响发布性能,但能确保消息可靠投递
  • 批量发布: 使用 PublishBatch 方法减少网络往返次数
  • 调整 BatchSize: 根据消息大小和网络延迟调整批量大小 (默认: 100, 建议: 50-500)
  • 禁用 PublisherConfirms: 生产环境如不需要绝对可靠性可禁用以提升性能
  • QoS 设置: PrefetchCount 限制未确认消息的数量,ConsumerDispatchConcurrency 控制消费者调度并发数
  • 错误处理: 框架内置重试机制和超时策略,失败的消息会根据配置进行重试
高级配置示例
顺序执行处理器
// 同一事件多个处理器按顺序执行(默认并行)
c.AddEvent<OrderEvent>(EModel.Routing, "order.exchange", "order.key", "order.queue")
 .ConfigureEvent(ec => ec.SequentialHandlerExecution = true) // 顺序执行
 .And();
高性能配置(高吞吐量场景)
builder.Services.AddRabbitBus(c =>
{
    // 高并发消费者设置
    c.WithConsumerSettings(dispatchConcurrency: 50, prefetchCount: 200);

    // 禁用发布确认以提升性能(生产环境可根据需要启用)
    c.WithResilience(retryCount: 3, publisherConfirms: false);

    // 提高处理器并发度
    c.WithHandlerConcurrency(handlerMaxDegreeOfParallelism: 8);

    // 事件配置
    c.AddEvent<HighVolumeEvent>(EModel.Routing, "highvol.exchange", "highvol.key", "highvol.queue")
     .WithEventQos(prefetchCount: 100) // 事件级QoS
     .And();
});
高可靠性配置(金融/关键业务场景)
builder.Services.AddRabbitBus(c =>
{
    // 保守的消费者设置
    c.WithConsumerSettings(dispatchConcurrency: 5, prefetchCount: 20);

    // 启用发布确认确保消息不丢失
    c.WithResilience(retryCount: 10, publisherConfirms: true);

    // 降低并发度保证稳定性
    c.WithHandlerConcurrency(handlerMaxDegreeOfParallelism: 2);

    // 事件配置
    c.AddEvent<CriticalEvent>(EModel.Routing, "critical.exchange", "critical.key", "critical.queue")
     .WithEventQos(prefetchCount: 10)
     .ConfigureEvent(ec => ec.SequentialHandlerExecution = true) // 顺序处理保证一致性
     .And();
});
集群连接配置
builder.Services.AddRabbitBus(c =>
{
    // 集群连接(多个节点)
    c.WithConnection(f =>
    {
        f.HostName = "rabbitmq-cluster";
        f.UserName = "user";
        f.Password = "password";
        f.Port = 5672;
        // 集群节点
        f.VirtualHost = "/";
    });

    // 其他配置...
});
性能调优指南
吞吐量优化
  • 增加 ConsumerDispatchConcurrency: 提高消费者调度并发数 (默认: 1, 建议: 10-50)
  • 调整 PrefetchCount: 根据消息处理速度调整预取数量 (默认: 50, 建议: 50-200)
  • HandlerMaxDegreeOfParallelism: 提高处理器并发度 (默认: 4, 建议: 4-16)
  • 禁用 PublisherConfirms: 生产环境如不需要绝对可靠性可禁用以提升性能
CPU 使用率控制
  • 降低 HandlerMaxDegreeOfParallelism: 防止 CPU 过载 (建议: 2-8)
  • 启用 SequentialHandlerExecution: 顺序执行减少并发开销
  • 监控系统负载: 根据实际 CPU 使用率调整并发参数
内存优化
  • 合理设置 PrefetchCount: 避免内存积压
  • 监控队列长度: 及时处理积压消息
  • 调整重试次数: 减少无效重试的内存占用
故障排除
常见问题
  1. 连接失败

    • 检查连接字符串格式
    • 确认 RabbitMQ 服务运行状态
    • 验证用户名密码和虚拟主机权限
  2. 消息丢失

    • 启用 PublisherConfirms
    • 检查消费者是否正确处理消息
    • 确认队列和交换机正确声明
  3. 性能问题

    • 检查 ConsumerDispatchConcurrency 设置
    • 监控 HandlerMaxDegreeOfParallelism 使用率
    • 分析消息处理时间瓶颈
  4. 内存泄漏

    • 确保消息正确确认(ack)
    • 检查处理器是否及时释放资源
    • 监控连接和通道数量
版本兼容性
  • 延迟队列: 需要 rabbitmq-delayed-message-exchange 插件
配置参数参考表
配置方法 参数 默认值 说明
WithConnection - - RabbitMQ 连接配置(主机、端口、认证等)
WithConsumerSettings dispatchConcurrency 1 消费者调度并发数,控制同时处理的消息数
prefetchCount 50 QoS 预取计数,限制未确认消息的数量
WithResilience retryCount 3 消息处理失败时的重试次数
publisherConfirms false 是否启用发布确认模式
maxOutstandingConfirms 1000 最大未确认发布数量
batchSize 100 批量发布大小
confirmTimeoutMs 30000 发布确认超时时间(毫秒)
WithApplication appName - 应用标识,用于日志和监控
WithHandlerConcurrency handlerMaxDegreeOfParallelism 4 单个事件处理器最大并发度
WithEventQos prefetchCount - 事件级 QoS 设置(覆盖全局设置)
WithEventHeaders headers - 消息头参数
WithEventQueueArgs args - 队列声明参数(x-max-priority 等)
WithEventExchangeArgs args - 交换机声明参数
ConfigureEvent SequentialHandlerExecution false 是否顺序执行同一事件的多个处理器
IgnoreHandler - - 忽略指定的处理器
WithSerializer - System.Text.Json 自定义消息序列化器
最佳实践
  1. 生产环境建议

    • 启用 PublisherConfirms 确保消息可靠性
    • 根据业务场景调整并发参数
    • 监控系统资源使用率
    • 设置合理的重试次数和超时时间
    • 使用批量发布提高高吞吐量场景性能
  2. 开发环境建议

    • 使用较低的并发设置便于调试
    • 启用详细日志记录
    • 使用默认序列化器简化开发
    • 测试批量发布功能
  3. 性能监控

    • 监控消息处理延迟
    • 跟踪消费者连接状态
    • 观察内存和 CPU 使用率
    • 定期检查队列积压情况
    • 监控发布确认的成功率
  4. 错误处理

    • 实现全局异常处理器
    • 配置死信队列处理失败消息
    • 设置监控告警机制
    • 记录详细的错误日志
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.25.905.150 117 9/5/2025
4.25.820.100 131 8/20/2025
4.25.814.175 137 8/14/2025
4.25.731.155 100 7/31/2025
4.25.724.1 492 7/23/2025
4.25.720.80 218 7/20/2025
4.25.716.42 121 7/15/2025
4.25.617.153 140 6/17/2025
4.25.616.190 131 6/16/2025
4.25.616.182 124 6/16/2025
4.25.613.111 269 6/13/2025
4.25.609.190 224 6/9/2025
4.25.609.181 214 6/9/2025
4.25.609.163 215 6/9/2025
4.25.609.140 200 6/9/2025
4.25.605.171 133 6/5/2025
4.25.605.104 138 6/5/2025
4.25.602.41 138 6/1/2025
4.25.526.140 136 5/26/2025
4.25.513.101 230 5/13/2025
4.25.506.150 139 5/6/2025
4.25.429.162 147 4/29/2025
4.25.429.103 170 4/29/2025
4.25.411.142 136 4/11/2025
4.25.409.92 152 4/9/2025
4.25.403.133 156 4/3/2025
4.25.319.113 167 3/19/2025
4.25.312.103 166 3/12/2025
4.25.227.135 104 2/27/2025
4.25.212.95 249 2/12/2025
4.25.211.140 106 2/11/2025
4.25.124.223 88 1/24/2025
3.24.1206.100 98 12/6/2024
3.24.1205.171 101 12/5/2024
3.24.1202.150 98 12/2/2024
3.24.1126.231 102 11/26/2024
3.24.1126.172 97 11/26/2024
3.24.1126.114 99 11/26/2024
3.24.1126.104 96 11/26/2024
3.24.1125.181 90 11/25/2024
3.24.1125.104 99 11/25/2024
3.24.1121.183 90 11/21/2024
3.24.1120.183 92 11/20/2024
3.24.1119.31 99 11/18/2024
3.24.1115.143 83 11/15/2024
3.24.1113.100 99 11/13/2024
3.24.1112.125 587 11/12/2024
3.24.1107.140 93 11/7/2024
3.24.1107.54 90 11/7/2024
3.24.1107.34 93 11/7/2024
3.24.1105.111 95 11/5/2024
3.24.1103.31 101 11/2/2024
3.24.1103 96 11/2/2024
3.24.1031.135 94 10/31/2024
3.24.1031.112 91 10/31/2024
3.24.1031.104 94 10/31/2024
3.24.1029.142 94 10/29/2024
3.24.1025.30 191 10/24/2024
3.24.1022.142 84 10/22/2024
3.24.1018.204 146 10/18/2024
3.24.1018.175 142 10/18/2024
3.24.1018.166 142 10/18/2024
3.24.1018.93 143 10/18/2024
3.24.1017.42 93 10/16/2024
3.24.1016.161 94 10/16/2024
3.24.1015.231 93 10/15/2024
3.24.1015.14 99 10/14/2024
3.24.1012.114 88 10/12/2024
3.24.1009.115 99 10/9/2024
3.24.1008.160 98 10/8/2024
3.24.1008.133 89 10/8/2024
3.24.1007.185 97 10/7/2024
3.24.1003.33 102 10/2/2024
3.24.1002.162 99 10/2/2024
3.24.929.143 95 9/29/2024
3.24.929.141 94 9/29/2024
3.24.929.131 96 9/29/2024
3.24.929.122 97 9/29/2024
3.24.926.184 101 9/26/2024
3.24.926.182 102 9/26/2024
3.24.926.175 104 9/26/2024
3.24.924.160 99 9/24/2024
3.24.924.133 105 9/24/2024
3.24.924.124 96 9/24/2024
3.24.924.10 112 9/23/2024
3.24.924.1 92 9/23/2024
3.24.923.234 98 9/23/2024
3.24.923.232 96 9/23/2024
3.24.923.155 95 9/23/2024
3.24.919.92 109 9/19/2024
3.24.914.125 102 9/14/2024
3.24.914.115 104 9/14/2024
3.24.914.111 107 9/14/2024
3.24.911.95 100 9/11/2024
3.24.908.215 93 9/8/2024
3.24.904.200 99 9/4/2024
3.24.828.163 104 8/28/2024
3.24.820.173 103 8/20/2024
3.24.814.92 114 8/14/2024
3.24.812.115 109 8/12/2024
3.24.802.100 86 8/2/2024
3.24.801.162 93 8/1/2024
3.24.801.160 93 8/1/2024
3.24.801.155 95 8/1/2024
3.24.730.164 86 7/30/2024
3.24.730.91 82 7/30/2024
3.24.724.91 88 7/24/2024
3.24.718.105 114 7/18/2024
3.24.716.95 98 7/16/2024
3.24.712.94 99 7/12/2024
3.24.710.14 94 7/9/2024
3.24.709.105 100 7/9/2024
3.24.704.94 103 7/4/2024
3.24.701.90 94 7/1/2024
3.24.628.114 105 6/28/2024
3.24.627.145 100 6/27/2024
3.24.620.160 106 6/20/2024
3.24.613.115 97 6/13/2024
3.24.612.95 106 6/12/2024
3.24.528.90 97 5/28/2024
3.24.522.84 114 5/22/2024
3.24.512.213 97 5/12/2024
3.24.508.112 114 5/8/2024
2.2024.428.71 106 4/28/2024
2.2024.427.1128 106 4/27/2024
2.2.72 125 4/14/2024
2.2.71 101 4/12/2024
2.2.8 104 4/26/2024
2.2.6 97 4/10/2024
2.2.5 123 3/26/2024
2.2.4 114 3/25/2024
2.2.3 109 3/24/2024
2.2.2 118 3/21/2024
2.2.1 118 3/20/2024
2.2.0 121 3/13/2024
2.1.9 113 2/21/2024
2.1.8 115 2/18/2024
2.1.7 120 2/16/2024
2.1.6 131 2/14/2024
2.1.5 106 2/14/2024
2.1.4 130 2/9/2024
2.1.3 114 2/8/2024
2.1.2 137 2/5/2024
2.1.1.2 187 12/26/2023
2.1.1.1 126 12/26/2023
2.1.1 123 12/25/2023
2.1.0 140 12/17/2023
2.0.11 156 12/6/2023
2.0.1 154 11/15/2023
2.0.0 114 11/14/2023
1.9.1 130 11/1/2023
1.9.0 128 10/19/2023
1.9.0-preview2 248 10/12/2023
1.9.0-preview1 103 10/12/2023
1.8.9 161 10/11/2023
1.8.8 153 10/11/2023
1.8.7-rc2 112 9/21/2023
1.8.7-rc1 108 9/12/2023
1.8.6 162 8/31/2023
1.8.5 592 8/25/2023
1.8.4 152 8/24/2023
1.8.3 149 8/23/2023
1.8.2 191 8/22/2023
1.8.1 151 8/18/2023
1.8.0 155 8/15/2023
1.7.9 179 8/11/2023
1.7.8 154 8/11/2023
1.7.7 164 8/10/2023
1.7.6 162 8/9/2023
1.7.5 187 8/9/2023
1.7.4 199 8/3/2023
1.7.3 170 8/1/2023
1.7.2 167 7/31/2023
1.7.1 160 7/27/2023
1.7.0 174 7/25/2023
1.6.9 171 7/25/2023
1.6.8 158 7/24/2023
1.6.7 175 7/20/2023
1.6.6 171 7/19/2023
1.6.5 140 7/19/2023
1.6.4 158 7/17/2023
1.6.3 158 7/17/2023
1.6.2 177 7/12/2023
1.6.1 177 6/30/2023
1.6.0 158 6/30/2023