Skip to content

Commit

Permalink
Make ConcurrentJobConfigurationShouldBeRespected a little less flaky
Browse files Browse the repository at this point in the history
Fix #167
  • Loading branch information
nulltoken committed Jan 20, 2025
1 parent f9457df commit c91dfa2
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 14 deletions.
22 changes: 18 additions & 4 deletions tests/NCronJob.Tests/NCronJobIntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -348,15 +348,29 @@ public async Task ConcurrentJobConfigurationShouldBeRespected()
.And.WithCronExpression("* * * * *").WithName("Job 2")
.And.WithCronExpression("* * * * *").WithName("Job 3")
.And.WithCronExpression("* * * * *").WithName("Job 4")));

var provider = CreateServiceProvider();

(IDisposable subscriber, IList<ExecutionProgress> events) = RegisterAnExecutionProgressSubscriber(provider);

await provider.GetRequiredService<IHostedService>().StartAsync(CancellationToken);

FakeTimer.Advance(TimeSpan.FromMinutes(1));
// Wait 2 instances at the same time
(await WaitForJobsOrTimeout(2, TimeSpan.FromMilliseconds(150))).ShouldBeTrue();
// But not another instance
(await WaitForJobsOrTimeout(1, TimeSpan.FromMilliseconds(50))).ShouldBeFalse();

await WaitUntilConditionIsMet(events, AtLeastTwoJobsAreInitializing);

subscriber.Dispose();

var runningJobs = events.Where(e => e.State == ExecutionState.Initializing).ToList();

Assert.Equal(2, runningJobs.Count);
Assert.NotEqual(runningJobs[0].CorrelationId, runningJobs[1].CorrelationId);

bool AtLeastTwoJobsAreInitializing(IList<ExecutionProgress> events)
{
var jobs = events.Where(e => e.State == ExecutionState.Initializing).ToList();
return jobs.Count >= 2;
}
}

[Fact]
Expand Down
36 changes: 26 additions & 10 deletions tests/NCronJob.Tests/TestHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Threading.Channels;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Time.Testing;
using Shouldly;

Expand Down Expand Up @@ -108,9 +109,9 @@ protected IEnumerable<Task> GetCompletionJobs(int expectedJobCount, Cancellation
}
}

protected static async Task WaitForOrchestrationCompletion(
protected async Task WaitUntilConditionIsMet(
IList<ExecutionProgress> events,
Guid orchestrationId)
Func<IList<ExecutionProgress>, bool> evaluator)
{
// Note: Although this function could seem a bit over-engineered, it's sadly necessary.
// Indeed, events may actually be updated upstream while it's being enumerated
Expand All @@ -119,26 +120,41 @@ protected static async Task WaitForOrchestrationCompletion(

int index = 0;

List<ExecutionProgress> tmp = [];

while (true)
{
int count = events.Count;

while (index < count)
{
ExecutionProgress @event = events[index];

if (@event.CorrelationId == orchestrationId && @event.State == ExecutionState.OrchestrationCompleted)
{
return;
}

tmp.Add(events[index]);
index++;
}

await Task.Delay(TimeSpan.FromMicroseconds(100));
if (evaluator(tmp))
{
return;
}

await Task.Delay(TimeSpan.FromMicroseconds(10), CancellationToken);
}
}

protected async Task WaitForOrchestrationCompletion(
IList<ExecutionProgress> events,
Guid orchestrationId)
{
await WaitUntilConditionIsMet(events, OrchestrationIsCompleted);

bool OrchestrationIsCompleted(IList<ExecutionProgress> events)
{
return events.Any(@event =>
@event.CorrelationId == orchestrationId &&
@event.State == ExecutionState.OrchestrationCompleted);
};

Check failure on line 155 in tests/NCronJob.Tests/TestHelper.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Remove this empty statement. (https://rules.sonarsource.com/csharp/RSPEC-1116)

Check failure on line 155 in tests/NCronJob.Tests/TestHelper.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-24.04-arm)

Remove this empty statement. (https://rules.sonarsource.com/csharp/RSPEC-1116)

Check failure on line 155 in tests/NCronJob.Tests/TestHelper.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Remove this empty statement. (https://rules.sonarsource.com/csharp/RSPEC-1116)
}

protected static (IDisposable subscriber, IList<ExecutionProgress> events) RegisterAnExecutionProgressSubscriber(IServiceProvider serviceProvider)
{
SynchronizedCollection<ExecutionProgress> events = [];
Expand Down

0 comments on commit c91dfa2

Please sign in to comment.