Skip to content

Commit 087c1c3

Browse files
committed
refactor: replace file-level #pragma warning disable 4014 with explicit discards
Use the discard operator (_ =) for intentionally unawaited Redis transaction-queued operations and a test fire-and-forget call, allowing the compiler to catch any future accidental unawaited async calls.
1 parent 4610e37 commit 087c1c3

2 files changed

Lines changed: 19 additions & 18 deletions

File tree

src/Foundatio.Redis/Queues/RedisQueue.cs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
using Foundatio.Redis.Utility;
1313
using Microsoft.Extensions.Logging;
1414
using StackExchange.Redis;
15-
#pragma warning disable 4014
1615

1716
namespace Foundatio.Queues;
1817

@@ -504,9 +503,10 @@ await _resiliencePolicy.ExecuteAsync(async _ => await Task.WhenAll(
504503

505504
var tx = Database.CreateTransaction();
506505
tx.AddCondition(Condition.KeyExists(GetRenewedTimeKey(entry.Id)));
507-
tx.ListRemoveAsync(_workListName, entry.Id);
508-
tx.ListLeftPushAsync(_waitListName, entry.Id);
509-
tx.KeyDeleteAsync(GetRenewedTimeKey(entry.Id));
506+
// Transaction-queued: commands execute atomically with ExecuteAsync(); individual results are not needed.
507+
_ = tx.ListRemoveAsync(_workListName, entry.Id);
508+
_ = tx.ListLeftPushAsync(_waitListName, entry.Id);
509+
_ = tx.KeyDeleteAsync(GetRenewedTimeKey(entry.Id));
510510
bool success = await _resiliencePolicy.ExecuteAsync(async _ => await tx.ExecuteAsync()).AnyContext();
511511
if (!success)
512512
throw new QueueException("Queue entry not in work list, it may have been auto abandoned.");
@@ -521,9 +521,10 @@ await _resiliencePolicy.ExecuteAsync(async _ => await Task.WhenAll(
521521

522522
var tx = Database.CreateTransaction();
523523
tx.AddCondition(Condition.KeyExists(GetRenewedTimeKey(entry.Id)));
524-
tx.ListRemoveAsync(_workListName, entry.Id);
525-
tx.ListLeftPushAsync(_queueListName, entry.Id);
526-
tx.KeyDeleteAsync(GetRenewedTimeKey(entry.Id));
524+
// Transaction-queued: commands execute atomically with ExecuteAsync(); individual results are not needed.
525+
_ = tx.ListRemoveAsync(_workListName, entry.Id);
526+
_ = tx.ListLeftPushAsync(_queueListName, entry.Id);
527+
_ = tx.KeyDeleteAsync(GetRenewedTimeKey(entry.Id));
527528
bool success = await _resiliencePolicy.ExecuteAsync(async _ => await tx.ExecuteAsync()).AnyContext();
528529
if (!success)
529530
throw new QueueException("Queue entry not in work list, it may have been auto abandoned.");
@@ -548,10 +549,11 @@ private async Task DeadLetterMessageAsync(IQueueEntry<T> entry, int? attempts =
548549

549550
var tx = Database.CreateTransaction();
550551
tx.AddCondition(Condition.KeyExists(GetRenewedTimeKey(entry.Id)));
551-
tx.ListRemoveAsync(_workListName, entry.Id);
552-
tx.ListLeftPushAsync(_deadListName, entry.Id);
553-
tx.KeyDeleteAsync(GetRenewedTimeKey(entry.Id));
554-
tx.KeyExpireAsync(GetPayloadKey(entry.Id), _options.DeadLetterTimeToLive);
552+
// Transaction-queued: commands execute atomically with ExecuteAsync(); individual results are not needed.
553+
_ = tx.ListRemoveAsync(_workListName, entry.Id);
554+
_ = tx.ListLeftPushAsync(_deadListName, entry.Id);
555+
_ = tx.KeyDeleteAsync(GetRenewedTimeKey(entry.Id));
556+
_ = tx.KeyExpireAsync(GetPayloadKey(entry.Id), _options.DeadLetterTimeToLive);
555557
bool success = await _resiliencePolicy.ExecuteAsync(async _ => await tx.ExecuteAsync()).AnyContext();
556558
if (!success)
557559
throw new QueueException("Queue entry not in work list, it may have been auto abandoned.");
@@ -724,9 +726,10 @@ public async Task DoMaintenanceWorkAsync()
724726
_logger.LogDebug("{WaitId}: Adding item back to queue for retry", waitId);
725727

726728
var tx = Database.CreateTransaction();
727-
tx.ListRemoveAsync(_waitListName, waitId);
728-
tx.ListLeftPushAsync(_queueListName, waitId);
729-
tx.KeyDeleteAsync(GetWaitTimeKey(waitId.ToString()));
729+
// Transaction-queued: commands execute atomically with ExecuteAsync(); individual results are not needed.
730+
_ = tx.ListRemoveAsync(_waitListName, waitId);
731+
_ = tx.ListLeftPushAsync(_queueListName, waitId);
732+
_ = tx.KeyDeleteAsync(GetWaitTimeKey(waitId.ToString()));
730733
bool success = await _resiliencePolicy.ExecuteAsync(async _ => await tx.ExecuteAsync()).AnyContext();
731734
if (!success)
732735
throw new Exception("Unable to move item to queue list.");

tests/Foundatio.Redis.Tests/Queues/RedisQueueTests.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
using StackExchange.Redis;
2121
using Xunit;
2222

23-
#pragma warning disable 4014
24-
2523
namespace Foundatio.Redis.Tests.Queues;
2624

2725
public class RedisQueueTests : QueueTestBase, IAsyncLifetime
@@ -594,8 +592,8 @@ public virtual async Task DatabaseTimeoutDuringDequeueHandledCorrectly()
594592
local now = tonumber(redis.call(""time"")[1]);
595593
while ((((tonumber(redis.call(""time"")[1]) - now))) < {DELAY_TIME_SEC}) do end";
596594

597-
// db will be busy for DELAY_TIME_SEC which will cause timeout on the dequeue to follow
598-
database.ScriptEvaluateAsync(databaseDelayScript);
595+
// Fire-and-forget: intentionally blocks Redis server-side to simulate timeout; result is not needed.
596+
_ = database.ScriptEvaluateAsync(databaseDelayScript);
599597

600598
var completion = new TaskCompletionSource<bool>();
601599
await queue.StartWorkingAsync(async (item) =>

0 commit comments

Comments
 (0)