Skip to content

Commit a91a224

Browse files
mohitpubnubMohit Tejanijakub-grzesiowskipubnub-release-bot
authored
refactor: improve request handling. (#247)
* consistency in value of NonSubscribeRequestTimeout to 15 as in PNConfiguration value at line 190 * additional condition to avoid null reference when debugging(during dev session) * eliminate possiblity of explicitly cancelling handshake request. * Status callback only gets non presence channel name, not exposing internal presence channel names * refactor(transport module client) to gracefully handle timeout and cancelled request scenario. * Added flags to get the information whether request is cancelled or timedout * refactor: applying timeouts as per configurations from middleware * fix(httpClient): Resource cleanup. * fix: remove timeout property set while making DELETE request. HtpClient internal status should not be changed between requests * revert: presence channel filteration. To preserve older version behaviour (v6) * Fix for UWP EE freeze * PubNub SDK v7.3.7.0 release. --------- Co-authored-by: Mohit Tejani <[email protected]> Co-authored-by: PUBNUB\jakub.grzesiowski <[email protected]> Co-authored-by: PubNub Release Bot <[email protected]>
1 parent f3bfc68 commit a91a224

23 files changed

+239
-124
lines changed

.pubnub.yml

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
name: c-sharp
2-
version: "7.3.6"
2+
version: "7.3.7"
33
schema: 1
44
scm: github.com/pubnub/c-sharp
55
changelog:
6+
- date: 2025-04-07
7+
version: v7.3.7
8+
changes:
9+
- type: improvement
10+
text: "Enhance request handling with detailed response interface."
611
- date: 2025-04-03
712
version: v7.3.6
813
changes:
@@ -877,7 +882,7 @@ features:
877882
- QUERY-PARAM
878883
supported-platforms:
879884
-
880-
version: Pubnub 'C#' 7.3.6
885+
version: Pubnub 'C#' 7.3.7
881886
platforms:
882887
- Windows 10 and up
883888
- Windows Server 2008 and up
@@ -888,7 +893,7 @@ supported-platforms:
888893
- .Net Framework 4.6.1+
889894
- .Net Framework 6.0
890895
-
891-
version: PubnubPCL 'C#' 7.3.6
896+
version: PubnubPCL 'C#' 7.3.7
892897
platforms:
893898
- Xamarin.Android
894899
- Xamarin.iOS
@@ -908,7 +913,7 @@ supported-platforms:
908913
- .Net Core
909914
- .Net 6.0
910915
-
911-
version: PubnubUWP 'C#' 7.3.6
916+
version: PubnubUWP 'C#' 7.3.7
912917
platforms:
913918
- Windows Phone 10
914919
- Universal Windows Apps
@@ -932,7 +937,7 @@ sdks:
932937
distribution-type: source
933938
distribution-repository: GitHub
934939
package-name: Pubnub
935-
location: https://github.com/pubnub/c-sharp/releases/tag/v7.3.6.0
940+
location: https://github.com/pubnub/c-sharp/releases/tag/v7.3.7.0
936941
requires:
937942
-
938943
name: ".Net"
@@ -1215,7 +1220,7 @@ sdks:
12151220
distribution-type: source
12161221
distribution-repository: GitHub
12171222
package-name: PubNubPCL
1218-
location: https://github.com/pubnub/c-sharp/releases/tag/v7.3.6.0
1223+
location: https://github.com/pubnub/c-sharp/releases/tag/v7.3.7.0
12191224
requires:
12201225
-
12211226
name: ".Net Core"
@@ -1574,7 +1579,7 @@ sdks:
15741579
distribution-type: source
15751580
distribution-repository: GitHub
15761581
package-name: PubnubUWP
1577-
location: https://github.com/pubnub/c-sharp/releases/tag/v7.3.6.0
1582+
location: https://github.com/pubnub/c-sharp/releases/tag/v7.3.7.0
15781583
requires:
15791584
-
15801585
name: "Universal Windows Platform Development"

CHANGELOG

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
v7.3.7 - April 07 2025
2+
-----------------------------
3+
- Modified: enhance request handling with detailed response interface.
4+
15
v7.3.6 - April 03 2025
26
-----------------------------
37
- Fixed: reafctor: Removed excess logging from transport module. Removed redundant logging from transport layer and added thread id information for tracking http request.

src/Api/PubnubApi/EndPoint/Files/SendFileOperation.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ private async Task<PNResult<PNFileUploadResult>> ProcessFileUpload()
426426
publishFailed = true;
427427
returnValue.Status = publishFileMessageStatus;
428428
logger?.Debug($"PublishFileMessage Failed. retry count={currentFileRetryCount}");
429-
await Task.Delay(1000);
429+
await Task.Delay(1000).ConfigureAwait(false);
430430
}
431431
} while (publishFailed && currentFileRetryCount <= publishFileRetryLimit &&
432432
!(publishFileMessageStatus?.StatusCode != 400 || publishFileMessageStatus.StatusCode != 403));

src/Api/PubnubApi/EndPoint/PubSub/PublishOperation.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,8 @@ internal void Publish(string channel, object message, bool storeInHistory, int t
204204

205205
PubnubInstance.transportMiddleware.Send(transportRequest).ContinueWith(t =>
206206
{
207-
var transportResponse = t.Result;
208-
if (transportResponse.Error == null)
207+
var transportResponse = t?.Result;
208+
if (transportResponse is { Error: null })
209209
{
210210
var responseString = Encoding.UTF8.GetString(transportResponse.Content);
211211
if (!string.IsNullOrEmpty(responseString))
@@ -304,7 +304,7 @@ internal async Task<PNResult<PNPublishResult>> Publish(string channel, object me
304304
var transportResponse =
305305
await PubnubInstance.transportMiddleware.Send(transportRequest).ConfigureAwait(false);
306306
logger?.Debug($"Publish() got transport response: {transportResponse?.StatusCode}\n error: {transportResponse?.Error?.Message}\nstackTrace: {transportResponse?.Error?.StackTrace}");
307-
if (transportResponse.Error == null)
307+
if (transportResponse is { Error: null, Content: not null })
308308
{
309309
string responseString = Encoding.UTF8.GetString(transportResponse.Content);
310310
PNStatus errorStatus = GetStatusIfError<PNPublishResult>(requestState, responseString);

src/Api/PubnubApi/EndPoint/PubSub/SubscribeManager2.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ public async Task<Tuple<HandshakeResponse, PNStatus>> HandshakeRequest(PNOperati
3333
if (config.MaintainPresenceState) presenceState = BuildJsonUserState(channels, channelGroups, true);
3434
var requestParameter = CreateSubscribeRequestParameter(channels: channels, channelGroups: channelGroups, timetoken: timetoken.GetValueOrDefault(), region: region.GetValueOrDefault(), stateJsonValue: presenceState, initialSubscribeUrlParams: initialSubscribeUrlParams, externalQueryParam: externalQueryParam);
3535
var transportRequest = pubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNSubscribeOperation);
36-
cancellationTokenSource = transportRequest.CancellationTokenSource;
3736
RequestState<HandshakeResponse> pubnubRequestState = new RequestState<HandshakeResponse>
3837
{
3938
Channels = channels,
@@ -43,16 +42,14 @@ public async Task<Tuple<HandshakeResponse, PNStatus>> HandshakeRequest(PNOperati
4342
Region = region.GetValueOrDefault(),
4443
TimeQueued = DateTime.Now
4544
};
46-
var transportResponse = await pubnubInstance.transportMiddleware.Send(transportRequest: transportRequest);
47-
45+
var transportResponse = await pubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ConfigureAwait(false);
4846
if (transportResponse.StatusCode == Constants.HttpRequestSuccessStatusCode && transportResponse.Error == null && transportResponse.Content != null) {
4947
var responseJson = Encoding.UTF8.GetString(transportResponse.Content);
5048
logger?.Debug($"Handshake Effect received json: {responseJson}");
5149
PNStatus status = new PNStatus(null, PNOperationType.PNSubscribeOperation, PNStatusCategory.PNConnectedCategory, channels, channelGroups);
5250
HandshakeResponse handshakeResponse = jsonLibrary.DeserializeToObject<HandshakeResponse>(responseJson);
5351
return new Tuple<HandshakeResponse, PNStatus>(handshakeResponse, status);
5452
}
55-
5653
PNStatus errStatus;
5754
if (transportResponse.Error != null) {
5855
PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(transportResponse.Error);
@@ -89,7 +86,8 @@ internal async Task<Tuple<ReceivingResponse<object>, PNStatus>> ReceiveRequest<T
8986
string channelsJsonState = BuildJsonUserState(channels, channelGroups, false);
9087
var requestParameter = CreateSubscribeRequestParameter(channels: channels, channelGroups: channelGroups, timetoken: timetoken.GetValueOrDefault(), region: region.GetValueOrDefault(), stateJsonValue: channelsJsonState, initialSubscribeUrlParams: initialSubscribeUrlParams, externalQueryParam: externalQueryParam);
9188
var transportRequest = pubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNSubscribeOperation);
92-
cancellationTokenSource = transportRequest.CancellationTokenSource;
89+
if (timetoken > 0)
90+
cancellationTokenSource = transportRequest.CancellationTokenSource;
9391
RequestState<ReceivingResponse<object>> pubnubRequestState = new RequestState<ReceivingResponse<object>>
9492
{
9593
Channels = channels,
@@ -100,14 +98,15 @@ internal async Task<Tuple<ReceivingResponse<object>, PNStatus>> ReceiveRequest<T
10098
TimeQueued = DateTime.Now
10199
};
102100

103-
var transportResponse = await pubnubInstance.transportMiddleware.Send(transportRequest: transportRequest);
101+
var transportResponse = await pubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ConfigureAwait(false);
104102
if (transportResponse.Content != null && transportResponse.Error == null && transportResponse.StatusCode == Constants.HttpRequestSuccessStatusCode) {
105103
var responseJson = Encoding.UTF8.GetString(transportResponse.Content);
106104
logger?.Debug($"Receiving Effect received json: {responseJson}");
107105
PNStatus status = new PNStatus(null, PNOperationType.PNSubscribeOperation, PNStatusCategory.PNConnectedCategory, channels, channelGroups);
108106
ReceivingResponse<object> receiveResponse = jsonLibrary.DeserializeToObject<ReceivingResponse<object>>(responseJson);
109107
return new Tuple<ReceivingResponse<object>, PNStatus>(receiveResponse, status);
110108
}
109+
if (transportResponse.IsCancelled) return resp;
111110
PNStatus errStatus;
112111
if (transportResponse.Error != null) {
113112
PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(transportResponse.Error);
@@ -132,13 +131,14 @@ internal void ReceiveRequestCancellation()
132131
if (cancellationTokenSource != null) {
133132
cancellationTokenSource.Cancel();
134133
cancellationTokenSource.Dispose();
134+
cancellationTokenSource = null;
135135
} else {
136-
logger?.Trace($"SubscribeManager RequestCancellation. No request to cancel.");
136+
logger?.Trace($"ReceiveRequestCancellation: No active request found to cancel.");
137137
}
138-
logger?.Trace($"SubscribeManager ReceiveRequestCancellation. Done.");
138+
logger?.Trace($"ReceiveRequestCancellation: Active request found and cancelled.");
139139
} catch (Exception ex)
140140
{
141-
logger?.Trace($"SubscribeManager ReceiveRequestCancellation Exception: {ex}");
141+
logger?.Trace($"ReceiveRequestCancellation Exception: {ex}");
142142
}
143143
}
144144

@@ -148,6 +148,7 @@ internal void ReceiveReconnectRequestCancellation()
148148
if (cancellationTokenSource != null) {
149149
cancellationTokenSource.Cancel();
150150
cancellationTokenSource.Dispose();
151+
cancellationTokenSource = null;
151152
} else {
152153
logger?.Trace($"SubscribeManager ReceiveReconnectRequestCancellation. No request to cancel.");
153154
}

src/Api/PubnubApi/EventEngine/Common/Delay.cs

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ namespace PubnubApi.EventEngine.Common
66
public class Delay
77
{
88
public bool Cancelled { get; private set; } = false;
9-
private readonly TaskCompletionSource<object> taskCompletionSource = new TaskCompletionSource<object>();
10-
private readonly object monitor = new object();
9+
private readonly TaskCompletionSource<object> taskCompletionSource = new ();
10+
private readonly CancellationTokenSource cancellationTokenSource = new ();
1111
private readonly int milliseconds;
1212

1313
public Delay(int milliseconds)
@@ -17,44 +17,37 @@ public Delay(int milliseconds)
1717

1818
public Task Start()
1919
{
20-
#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12
21-
Task taskAwaiter = Task.Factory.StartNew(AwaiterLoop);
22-
taskAwaiter.Wait();
23-
#else
24-
Thread awaiterThread = new Thread(AwaiterLoop);
25-
awaiterThread.Start();
26-
#endif
20+
AwaiterLoop();
2721
return taskCompletionSource.Task; }
2822

2923
public void Cancel()
3024
{
31-
lock (monitor)
32-
{
33-
Cancelled = true;
34-
Monitor.Pulse(monitor);
35-
}
25+
Cancelled = true;
26+
cancellationTokenSource.Cancel();
3627
}
3728

38-
private void AwaiterLoop()
29+
private async void AwaiterLoop()
3930
{
40-
while(true)
31+
if (Cancelled)
32+
{
33+
taskCompletionSource.TrySetCanceled();
34+
return;
35+
}
36+
try
37+
{
38+
await Task.Delay(milliseconds, cancellationTokenSource.Token).ConfigureAwait(false);
39+
}
40+
catch (TaskCanceledException e)
41+
{
42+
taskCompletionSource.TrySetCanceled();
43+
return;
44+
}
45+
if (Cancelled)
4146
{
42-
lock (monitor)
43-
{
44-
if (Cancelled)
45-
{
46-
taskCompletionSource.TrySetCanceled();
47-
break;
48-
}
49-
Monitor.Wait(monitor, milliseconds);
50-
if (Cancelled)
51-
{
52-
taskCompletionSource.TrySetCanceled();
53-
break;
54-
}
55-
taskCompletionSource.TrySetResult(null);
56-
}
47+
taskCompletionSource.TrySetCanceled();
48+
return;
5749
}
50+
taskCompletionSource.TrySetResult(null);
5851
}
5952
}
6053
}

src/Api/PubnubApi/EventEngine/Core/EffectDispatcher.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public async Task Dispatch(IEffectInvocation invocation) {
2828
if (handler.IsBackground(invocation))
2929
FireAndForget(handler, invocation);
3030
else
31-
await handler.Run(invocation);
31+
await handler.Run(invocation).ConfigureAwait(false);
3232
}
3333
}
3434

src/Api/PubnubApi/EventEngine/Core/Engine.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ private async Task Transition(IEvent e)
6666
return;
6767
}
6868

69-
await ExecuteStateChange(currentState, stateInvocationPair.State, stateInvocationPair.Invocations);
69+
await ExecuteStateChange(currentState, stateInvocationPair.State, stateInvocationPair.Invocations).ConfigureAwait(false);
7070

7171
this.currentState = stateInvocationPair.State;
7272
}
@@ -78,16 +78,16 @@ private async Task ExecuteStateChange(State sourceState, State targetState, IEnu
7878
logger?.Debug($"Exiting state {sourceState}");
7979
foreach (var effectInvocation in sourceState.OnExit ?? emptyInvocationList) {
8080
logger?.Debug($"Dispatching effect: {effectInvocation}");
81-
await dispatcher.Dispatch(effectInvocation);
81+
await dispatcher.Dispatch(effectInvocation).ConfigureAwait(false);
8282
}
8383
foreach (var effectInvocation in invocations ?? emptyInvocationList) {
8484
logger?.Debug($"Dispatching effect: {effectInvocation}");
85-
await dispatcher.Dispatch(effectInvocation);
85+
await dispatcher.Dispatch(effectInvocation).ConfigureAwait(false);
8686
}
8787
logger?.Debug($"Entering state {targetState}");
8888
foreach (var effectInvocation in targetState.OnEntry ?? emptyInvocationList) {
8989
logger?.Debug($"Dispatching effect: {effectInvocation}");
90-
await dispatcher.Dispatch(effectInvocation);
90+
await dispatcher.Dispatch(effectInvocation).ConfigureAwait(false);
9191
}
9292
}
9393
}

src/Api/PubnubApi/EventEngine/Presence/Effects/DelayedHeartbeatEffectHandler.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ public override async Task Run(DelayedHeartbeatInvocation invocation)
3434
return;
3535
}
3636
retryDelay = new Delay(retryConfiguration.RetryPolicy.GetDelay(invocation.RetryCount, invocation.Reason, null));
37-
await retryDelay.Start();
37+
await retryDelay.Start().ConfigureAwait(false);
3838
if (!retryDelay.Cancelled)
39-
await MakeHeartbeatRequest(invocation);
39+
await MakeHeartbeatRequest(invocation).ConfigureAwait(false);
4040
}
4141

4242
private void EnqueueHeartbeatGiveUpEvent()
@@ -49,7 +49,7 @@ private async Task MakeHeartbeatRequest(DelayedHeartbeatInvocation invocation)
4949
var resp = await heartbeatOperation.HeartbeatRequest<string>(
5050
invocation.Input.Channels.ToArray(),
5151
invocation.Input.ChannelGroups.ToArray()
52-
);
52+
).ConfigureAwait(false);
5353
switch (resp) {
5454
case { } when resp.Error:
5555
eventQueue.Enqueue(new Events.HeartbeatFailureEvent() { retryCount = invocation.RetryCount + 1, Status = resp });

src/Api/PubnubApi/EventEngine/Presence/Effects/HeartbeatEffectHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public override async Task Run(HeartbeatInvocation invocation)
2525
var resp = await heartbeatOperation.HeartbeatRequest<string>(
2626
invocation.Input.Channels.ToArray(),
2727
invocation.Input.ChannelGroups.ToArray()
28-
);
28+
).ConfigureAwait(false);
2929
switch (resp) {
3030
case { } when resp.Error:
3131
eventQueue.Enqueue(new Events.HeartbeatFailureEvent() { retryCount = 0, Status = resp });

0 commit comments

Comments
 (0)