Skip to content

Commit

Permalink
Add docs about TimeoutException thrown in consumer using HTTPClient. (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
yang-xiaodong committed Jul 8, 2023
1 parent 652207c commit 11127e2
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 112 deletions.
3 changes: 3 additions & 0 deletions docs/content/user-guide/en/cap/messaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

The data sent by using the `ICapPublisher` interface is called `Message`.

!!! WARNING "TimeoutException thrown in consumer using HTTPClient"
By default, if the consumer throws an `OperationCanceledException` (including `TaskCanceledException`), we consider this to be normal user behavior and ignore the exception. If you use HTTPClient in the consumer method and configure the request timeout, due to the [design issue](https://github.com/dotnet/runtime/issues/21965) of HTTP Client, you may need to handle the exception separately and re-throw non `OperationCanceledException`, refer to #1368.

## Compensating transaction

Wiki :
Expand Down
54 changes: 0 additions & 54 deletions docs/content/user-guide/en/cap/serialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,57 +29,3 @@ services.AddSingleton<ISerializer, YourSerializer>();
services.AddCap
```

## Message Adapter (removed in v3.0)

In heterogeneous systems, sometimes you need to communicate with other systems, but other systems use message objects that may be different from CAP's [**Wrapper Object**](../storage/general.md#_7). This time maybe you need to customize the message wapper.

CAP provides the `IMessagePacker` interface for customizing the [**Wrapper Object**](../storage/general.md#_7). Custom MessagePacker usually packs and unpacks the `CapMessage` In this process you can add your own business objects.

Usage :

```csharp

class MyMessagePacker : IMessagePacker
{
private readonly IContentSerializer _serializer;

public DefaultMessagePacker(IContentSerializer serializer)
{
_serializer = serializer;
}

public string Pack(CapMessage obj)
{
var myStructure = new
{
Id = obj.Id,
Body = obj.Content,
Date = obj.Timestamp,
Callback = obj.CallbackName
};
return _serializer.Serialize(myStructure);
}

public CapMessage UnPack(string packingMessage)
{
var myStructure = _serializer.DeSerialize<MyStructure>(packingMessage);

return new CapMessageDto
{
Id = myStructure.Id,
Timestamp = myStructure.Date,
Content = myStructure.Body,
CallbackName = myStructure.Callback
};
}
}
```

Next, add the custom `MyMessagePacker` to the service.

```csharp

services.AddCap(x =>{ }).AddMessagePacker<MyMessagePacker>();

```
3 changes: 3 additions & 0 deletions docs/content/user-guide/zh/cap/messaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

你可以阅读 [quick-start](../getting-started/quick-start.md#_3) 来学习如何发送和处理消息。

!!! WARNING "消费者中使用 HTTPClient 引发的 TimeoutException"
默认情况下,如果消费者抛出 `OperationCanceledException`(包括 `TaskCanceledException`),我们会认为这是用户的正常行为而对异常进行忽略。如果你在消费者方法中使用 HTTPClient 并且进行了配置了Timeout配置,由于HTTP Client的[设计问题](https://github.com/dotnet/runtime/issues/21965),你可能需要单独对异常进行处理并重新引发非OperationCanceledException,参考 #1368

## 补偿事务

[Compensating transaction](https://en.wikipedia.org/wiki/Compensating_transaction)
Expand Down
55 changes: 0 additions & 55 deletions docs/content/user-guide/zh/cap/serialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,59 +29,4 @@ services.AddSingleton<ISerializer, YourSerializer>();
// ---
services.AddCap
```


## 消息适配器 (v3.0移除 )

在异构系统中,有时候需要和其他系统进行通讯,但是其他系统使用的消息对象可能和 CAP 的[**包装器对象**](../storage/general.md#_7)不一样,这个时候就需要对消息进行自定义适配。

CAP 提供了 `IMessagePacker` 接口用于对 [**包装器对象**](../storage/general.md#_7) 进行自定义,自定义的 MessagePacker 通常是将 `CapMessage` 进行打包和解包操作,在这个过程中可以添加自己的业务对象。

使用方法:

```csharp

class MyMessagePacker : IMessagePacker
{
private readonly IContentSerializer _serializer;

public DefaultMessagePacker(IContentSerializer serializer)
{
_serializer = serializer;
}

public string Pack(CapMessage obj)
{
var myStructure = new
{
Id = obj.Id,
Body = obj.Content,
Date = obj.Timestamp,
Callback = obj.CallbackName
};
return _serializer.Serialize(myStructure);
}

public CapMessage UnPack(string packingMessage)
{
var myStructure = _serializer.DeSerialize<MyStructure>(packingMessage);

return new CapMessageDto
{
Id = myStructure.Id,
Timestamp = myStructure.Date,
Content = myStructure.Body,
CallbackName = myStructure.Callback
};
}
}
```

接下来,配置自定义的 `MyMessagePacker` 到服务中。

```csharp

services.AddCap(x =>{ }).AddMessagePacker<MyMessagePacker>();

```
20 changes: 19 additions & 1 deletion samples/Sample.ConsoleApp/EventSubscriber.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using DotNetCore.CAP;

namespace Sample.ConsoleApp
{
public class EventSubscriber : ICapSubscribe
{
[CapSubscribe("sample.console.showtime")]
public void ShowTime(DateTime date)
public async Task ShowTime(DateTime date)
{
Console.WriteLine(date);

string baseAddress = "http://localhost:8080/";
var client = new HttpClient()
{
BaseAddress = new Uri(baseAddress),
Timeout = TimeSpan.FromMilliseconds(10)
};
//try
//{
var s = await client.GetAsync(baseAddress);
//}
//catch (Exception e)
//{
// Console.WriteLine(e.Message);
// Console.WriteLine(e.InnerException.Message);
//}
}
}
}
35 changes: 33 additions & 2 deletions samples/Sample.ConsoleApp/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Threading.Tasks;
using DotNetCore.CAP;
using DotNetCore.CAP.Filter;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Savorboard.CAP.InMemoryMessageQueue;
Expand All @@ -10,6 +12,7 @@ public class Program
{
public static void Main(string[] args)
{
var cts = new System.Threading.CancellationTokenSource();
var container = new ServiceCollection();

container.AddLogging(x => x.AddConsole());
Expand All @@ -19,15 +22,43 @@ public static void Main(string[] args)
x.UseInMemoryStorage();
x.UseInMemoryMessageQueue();
});
}).AddSubscribeFilter<Filter>();

container.AddSingleton<EventSubscriber>();

var sp = container.BuildServiceProvider();

sp.GetService<IBootstrapper>().BootstrapAsync();
sp.GetService<IBootstrapper>().BootstrapAsync(cts.Token);

_ = Task.Run(async () =>
{
while (!cts.IsCancellationRequested)
{
await Task.Delay(2000, cts.Token);
await sp.GetService<ICapPublisher>().PublishAsync("sample.console.showtime", DateTime.Now, cancellationToken: cts.Token);
}
}, cts.Token);

AppDomain.CurrentDomain.ProcessExit += (_, _) =>
{
cts.Cancel();
};

Console.ReadLine();
}
}

public class Filter : SubscribeFilter
{
public override Task OnSubscribeExceptionAsync(ExceptionContext context)
{
if (context.Exception.InnerException is TimeoutException)
{
throw new TimeoutException("Http request timeout");
}

return base.OnSubscribeExceptionAsync(context);
}
}
}

0 comments on commit 11127e2

Please sign in to comment.