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

C#控制台应用调用独立方法时出现Dapr消息发布异常

在Kubernetes Cron Job中使用Dapr Sidecar时独立方法调用失败的解决方案

问题场景

将C#控制台应用作为Kubernetes Cron Job运行,通过Dapr Sidecar向Azure Service Bus队列发布消息时出现异常:Main方法内直接发布消息可正常执行,但调用独立方法PublishMessage时触发DaprException,报错连接被拒绝。

代码示例

static async Task Main(string[] args)
{
    using (var client = new DaprClientBuilder().Build())
    {
        string topicName = "topic1";
        await client.PublishEventAsync("pubsub", topicName, "testdapr2");               
        Console.WriteLine("Message published successfully.");
    }
    await PublishMessage();
}

private static async Task PublishMessage()
{
    Console.WriteLine("Getting Error");
    using (var client = new DaprClientBuilder().Build())
    {
        string topicName = "topic1";
        await client.PublishEventAsync("pubsub", topicName, "testdapr2");
        Console.WriteLine("Message published successfully.");
    }
}

报错信息

DaprException: Publish operation failed: the Dapr endpoint indicated a failure. See InnerException for details.
---> Grpc.Core.RpcException: Status(StatusCode="Unavailable", Detail="Error connecting to subchannel.", DebugException="System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it.")
---> System.Net.Sockets.SocketException (10061): No connection could be made because the target machine actively refused it.
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|281_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
at Grpc.Net.Client.Balancer.Internal.SocketConnectivitySubchannelTransport.TryConnectAsync(ConnectContext context)
--- End of inner exception stack trace ---
at Grpc.Net.Client.Balancer.Internal.ConnectionManager.PickAsync(PickContext context, Boolean waitForReady, CancellationToken cancellationToken)
at Grpc.Net.Client.Balancer.Internal.BalancerHttpHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Grpc.Net.Client.Internal.GrpcCall`2.RunCall(HttpRequestMessage request, Nullable`1 timeout)
at Dapr.Client.DaprClientGrpc.MakePublishRequest(String pubsubName, String topicName, ByteString content, Dictionary`2 metadata, String dataContentType, CancellationToken cancellationToken)
--- End of inner exception stack trace ---

问题分析

核心原因是Kubernetes Cron Job的生命周期与Dapr Sidecar的绑定逻辑:

  1. 当Main方法中第一个using块释放Dapr客户端后,控制台应用主进程的状态变化会被Dapr的注入机制感知到,Sidecar容器可能被提前终止。
  2. 后续调用PublishMessage方法创建新客户端时,Sidecar已经停止,导致无法建立连接,触发连接拒绝的Socket异常。

解决方案

1. 复用Dapr客户端实例

避免在每个方法中重复创建Dapr客户端,改为在应用启动时创建单例实例,整个执行周期内复用,确保客户端始终能连接到存活的Sidecar。

修改后的代码:

// 全局复用的Dapr客户端实例
private static readonly DaprClient _daprClient = new DaprClientBuilder().Build();

static async Task Main(string[] args)
{
    try
    {
        string topicName = "topic1";
        await _daprClient.PublishEventAsync("pubsub", topicName, "testdapr2");               
        Console.WriteLine("Message published successfully from Main.");
        
        await PublishMessage();
    }
    finally
    {
        // 应用结束时释放客户端资源
        (_daprClient as IDisposable)?.Dispose();
    }
}

private static async Task PublishMessage()
{
    Console.WriteLine("Publishing message from separate method");
    string topicName = "topic1";
    await _daprClient.PublishEventAsync("pubsub", topicName, "testdapr2");
    Console.WriteLine("Message published successfully from separate method.");
}

2. 调整Sidecar终止等待时长

在Kubernetes Cron Job的Pod模板中添加Dapr注解,延长Sidecar的终止等待时间,确保主进程完成所有异步操作后,Sidecar才会终止。

示例YAML配置片段:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: dapr-cron-job
spec:
  schedule: "*/5 * * * *"
  jobTemplate:
    spec:
      template:
        metadata:
          annotations:
            dapr.io/enabled: "true"
            dapr.io/app-id: "cron-app"
            dapr.io/app-port: "80"
            # 设置Sidecar终止等待30秒
            dapr.io/termination-grace-period: "30"
        spec:
          containers:
          - name: cron-app
            image: your-app-image:latest
          restartPolicy: OnFailure

3. 确保主进程等待所有异步任务完成

虽然代码中使用了await,但控制台应用可能存在异步任务未完全执行就开始退出的情况。可以在Main方法末尾添加额外的等待逻辑,或者使用Task.WhenAll确保所有任务完成:

static async Task Main(string[] args)
{
    try
    {
        var mainPublishTask = _daprClient.PublishEventAsync("pubsub", "topic1", "testdapr2");
        var separatePublishTask = PublishMessage();
        
        // 等待所有发布任务完成
        await Task.WhenAll(mainPublishTask, separatePublishTask);
        
        Console.WriteLine("All messages published successfully.");
    }
    finally
    {
        (_daprClient as IDisposable)?.Dispose();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 01:22:32