Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support to scheduler message #3487

Open
wants to merge 40 commits into
base: master
Choose a base branch
from

Conversation

lillo42
Copy link
Contributor

@lillo42 lillo42 commented Jan 20, 2025

  • Remove unnecessary code
  • Fixes build
  • Add Unit test
  • Finish implementation
  • Add Sample
  • Implement support to HangFire
  • Implement support for Quartz
  • Implement support for AWS Scheduler
  • Implement support for Azure

Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Health Quality Gates: FAILED

Change in average Code Health of affected files: -0.02 (8.17 -> 8.15)

  • Declining Code Health: 4 findings(s) 🚩

  • Affected Hotspots: 2 files(s) 🔥

View detailed results in CodeScene

Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Health Quality Gates: FAILED

Change in average Code Health of affected files: -0.02 (8.17 -> 8.15)

  • Declining Code Health: 4 findings(s) 🚩

  • Affected Hotspots: 2 files(s) 🔥

View detailed results in CodeScene

@iancooper iancooper added 2 - In Progress grabbed by assignee feature request .NET Pull requests that update .net code Draft This is a work in progress labels Jan 22, 2025
Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Health Quality Gates: FAILED

Change in average Code Health of affected files: -0.16 (8.69 -> 8.53)

  • Declining Code Health: 12 findings(s) 🚩
  • Improving Code Health: 2 findings(s) ✅
  • Affected Hotspots: 7 files(s) 🔥

View detailed results in CodeScene

@@ -31,6 +31,7 @@ THE SOFTWARE. */
using Microsoft.Extensions.Logging;
using Paramore.Brighter.Logging;
using Paramore.Brighter.Observability;
using Paramore.Brighter.Scheduler.Events;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ Getting worse: Code Duplication
introduced similar code in: CreateMessageFromRequest,CreateMessageFromRequestAsync

Suppress

@@ -27,6 +27,7 @@ THE SOFTWARE. */
using System.Threading.Tasks;
using Confluent.Kafka;
using Microsoft.Extensions.Logging;
using Paramore.Brighter.Tasks;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Getting better: Code Duplication
reduced similar code in: Send,SendAsync

Comment on lines +114 to +137
{
delay ??= TimeSpan.Zero;
if (delay != TimeSpan.Zero)
{
if (Scheduler is IAmAMessageSchedulerSync sync)
{
sync.Schedule(message, delay.Value);
return;
}

if (Scheduler is IAmAMessageSchedulerAsync async)
{
BrighterAsyncContext.Run(async () => await async.ScheduleAsync(message, delay.Value));
return;
}

s_logger.LogWarning("MsSqlMessageProducer: no scheduler configured, message will be sent immediately");
}

var topic = message.Header.Topic;

s_logger.LogDebug("MsSqlMessageProducer: send message with topic {Topic} and id {Id}", topic, message.Id);

_sqlQ.Send(message, topic);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ New issue: Code Duplication
The module contains 2 functions with similar structure: SendWithDelay,SendWithDelayAsync

Suppress

@@ -42,6 +42,7 @@ public static class BrighterSpanExtensions
CommandProcessorSpanOperation.Send => "send",
CommandProcessorSpanOperation.Clear => "clear",
CommandProcessorSpanOperation.Archive => "archive",
CommandProcessorSpanOperation.Scheduler => "scheduler",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ Getting worse: Complex Method
ToSpanName increases in cyclomatic complexity from 9 to 10, threshold = 9

Suppress

Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Health Quality Gates: FAILED

Change in average Code Health of affected files: -0.16 (8.69 -> 8.53)

  • Declining Code Health: 12 findings(s) 🚩
  • Improving Code Health: 2 findings(s) ✅
  • Affected Hotspots: 7 files(s) 🔥

View detailed results in CodeScene

Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Health Quality Gates: FAILED

Change in average Code Health of affected files: -0.15 (8.69 -> 8.54)

  • Declining Code Health: 13 findings(s) 🚩
  • Improving Code Health: 2 findings(s) ✅
  • Affected Hotspots: 7 files(s) 🔥

View detailed results in CodeScene

Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Health Quality Gates: FAILED

Change in average Code Health of affected files: -0.15 (8.69 -> 8.54)

  • Declining Code Health: 13 findings(s) 🚩
  • Improving Code Health: 2 findings(s) ✅
  • Affected Hotspots: 7 files(s) 🔥

View detailed results in CodeScene

Copy link
Member

@iancooper iancooper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First, there is a tremendous amount of work here, that has broken the back of this. So thank you so much. I think my thoughts are generally:

  • Let's overload existing methods to take a DateTimeOffset scheduledAt parameter (and provide a helper method to create a scheduledAt from a TimeSpan that represents a delay) over new method names
  • We have different job types: Request (from CP goes back to send, post or publish, you need to know which) and Message (from a consumer implementation, used to delay posting a message, comes back to the consumer )
  • That makes your scheduler a bit more gnarly; you want an interface that the 3rd party lib support implements that offers either.

But once we have that this will solve a massive problem for us with supporting a Send at a point in time, which will be a really powerful addition in V10

```c#
public interface IAmACommandProcessor
{
string SchedulerSend<TRequest>(TimeSpan delay, TRequest request) where TRequest : class, IRequest;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we would be better off overloading Send with a time, than adding a new name here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, how about SendAt, PublishAt, PostAt etc.


if (Scheduler is IAmAMessageSchedulerSync sync)
{
sync.Schedule(message, delay.Value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably have to rename to strategy used above

return;
}

if (Scheduler is IAmAMessageSchedulerSync sync)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we assume that an async path, always has an async scheduler, and only use the sync scheduler on a sync path (or if transport does not support sync and async, just resort to whichever matches? This allows us to make a blocking decision via the Brighter Sync Context

}
}

public async Task<string> SchedulerPostAsync<TRequest>(TRequest request,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same comments apply. Overload with an At parameter over a new method convention; only one scheduler type

src/Paramore.Brighter/InMemoryMessageScheduler.cs Outdated Show resolved Hide resolved
}

/// <inheritdoc cref="Dispose"/>
public void Dispose()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to ensure we dispose any remaining timers here?

var message = JsonSerializer.Deserialize<Message>(obj!, JsonSerialisationOptions.Options)!;
if (async)
{
await processor.PostAsync(new FireSchedulerMessage { Id = id, Message = message });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works if our intent is always to send a message, but on a Send or Publish intent is actually just to delay Send or Publish.

delay ??= TimeSpan.Zero;
if (delay != TimeSpan.Zero)
{
if (Scheduler is IAmAMessageSchedulerAsync async)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usual comments on name and pick one

Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Health Improved (1 files improve in Code Health)

Gates Failed
Prevent hotspot decline (5 hotspots with Code Duplication, Complex Method, Large Method)
Enforce critical code health rules (2 files with Bumpy Road Ahead)
Enforce advisory code health rules (11 files with Code Duplication, Complex Method, Large Method, Excess Number of Function Arguments)

Gates Passed
1 Quality Gates Passed

See analysis details in CodeScene

Reason for failure
Prevent hotspot decline Violations Code Health Impact
CommandProcessor.cs 1 rule in this hotspot 8.28 → 7.33 Suppress
RmqMessageProducer.cs 1 rule in this hotspot 9.39 → 9.10 Suppress
OutboxProducerMediator.cs 1 rule in this hotspot 7.38 → 7.16 Suppress
ControlBusReceiverBuilder.cs 1 rule in this hotspot 8.46 → 8.46 Suppress
ServiceCollectionExtensions.cs 1 rule in this hotspot 8.56 → 9.06 Suppress
Enforce critical code health rules Violations Code Health Impact
InMemoryScheduler.cs 1 critical rule 10.00 → 9.24 Suppress
FireSchedulerRequestHandler.cs 1 critical rule 10.00 → 9.39 Suppress
Enforce advisory code health rules Violations Code Health Impact
CommandProcessor.cs 1 advisory rule 8.28 → 7.33 Suppress
InMemoryScheduler.cs 1 advisory rule 10.00 → 9.24 Suppress
MsSqlMessageProducer.cs 1 advisory rule 10.00 → 9.39 Suppress
QuartzScheduler.cs 1 advisory rule 10.00 → 9.39 Suppress
AwsScheduler.cs 1 advisory rule 10.00 → 9.69 Suppress
KafkaMessageProducer.cs 1 advisory rule 9.39 → 9.10 Suppress
RmqMessageProducer.cs 1 advisory rule 9.39 → 9.10 Suppress
OutboxProducerMediator.cs 1 advisory rule 7.38 → 7.16 Suppress
BrighterSpanExtensions.cs 1 advisory rule 9.50 → 9.47 Suppress
ControlBusReceiverBuilder.cs 1 advisory rule 8.46 → 8.46 Suppress
ServiceCollectionExtensions.cs 1 advisory rule 8.56 → 9.06 Suppress
View Improvements
File Code Health Impact Categories Improved
ServiceCollectionExtensions.cs 8.56 → 9.06 Code Duplication
KafkaMessageProducer.cs 9.39 → 9.10 Code Duplication
RedisMessageProducer.cs no change Code Duplication

Quality Gate Profile: Clean Code Collective
Want more control? Customize Code Health rules or catch issues early with our IDE extension and CLI tool.

@@ -37,6 +37,7 @@ THE SOFTWARE. */
using Paramore.Brighter.FeatureSwitch;
using Paramore.Brighter.Logging;
using Paramore.Brighter.Observability;
using Paramore.Brighter.Tasks;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ Getting worse: Code Duplication
introduced similar code in: Post,Post,PostAsync,PostAsync and 4 more functions

Suppress

@@ -24,6 +24,7 @@ THE SOFTWARE. */
#endregion

using System;
using System.Linq;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No longer an issue: Code Duplication
The module no longer contains too many functions with similar structure

@@ -178,6 +178,7 @@ public Dispatcher Build(string hostName)
.ExternalBus(ExternalBusType.FireAndForget, mediator)
.ConfigureInstrumentation(null, InstrumentationOptions.None)
.RequestContextFactory(new InMemoryRequestContextFactory())
.RequestSchedulerFactory(new InMemorySchedulerFactory())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ Getting worse: Large Method
Build increases from 73 to 74 lines of code, threshold = 70

Suppress

Comment on lines +223 to +232
public void SendWithDelay(Message message, TimeSpan? delay = null)
{
delay ??= TimeSpan.Zero;
if (delay != TimeSpan.Zero)
{
var schedulerSync = (IAmAMessageSchedulerSync)Scheduler!;
schedulerSync.Schedule(message, delay.Value);
return;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ New issue: Complex Method
SendWithDelay has a cyclomatic complexity of 10, threshold = 9

Suppress

Comment on lines +412 to +460
private async Task<string> ScheduleAsync(
Message message,
string id,
DateTimeOffset at,
bool async,
CancellationToken cancellationToken = default)
{
await EnsureGroupExistsAsync(cancellationToken);
var target = await CreateTargetAsync(id, message, async);

using var client = factory.CreateSchedulerClient();
try
{
await client.CreateScheduleAsync(
new CreateScheduleRequest
{
Name = id,
GroupName = schedulerGroup.Name,
Target = target,
ScheduleExpression = AtExpression(at),
ScheduleExpressionTimezone = "UTC",
State = ScheduleState.ENABLED,
ActionAfterCompletion = ActionAfterCompletion.DELETE,
FlexibleTimeWindow = scheduler.ToFlexibleTimeWindow()
}, cancellationToken);
}
catch (ConflictException)
{
if (scheduler.OnConflict == OnSchedulerConflict.Throw)
{
throw;
}

await client.UpdateScheduleAsync(
new UpdateScheduleRequest
{
Name = id,
GroupName = schedulerGroup.Name,
Target = target,
ScheduleExpression = AtExpression(at),
ScheduleExpressionTimezone = "UTC",
State = ScheduleState.ENABLED,
ActionAfterCompletion = ActionAfterCompletion.DELETE,
FlexibleTimeWindow = scheduler.ToFlexibleTimeWindow()
}, cancellationToken);
}

return id;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ New issue: Excess Number of Function Arguments
ScheduleAsync has 5 arguments, threshold = 4

Suppress

Comment on lines +23 to +40
public string Schedule(Message message, DateTimeOffset at)
{
var id = getOrCreateMessageSchedulerId(message);
var job = JobBuilder.Create<QuartzBrighterJob>()
.WithIdentity(id, group!)
.UsingJobData("message", JsonSerializer.Serialize(
new FireSchedulerMessage { Id = id, Async = false, Message = message },
JsonSerialisationOptions.Options))
.Build();

var trigger = TriggerBuilder.Create()
.WithIdentity(id + "-trigger", group!)
.StartAt(at)
.Build();

BrighterAsyncContext.Run(async () => await scheduler.ScheduleJob(job, trigger));
return id;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ New issue: Code Duplication
The module contains 4 functions with similar structure: Schedule,Schedule,ScheduleAsync,ScheduleAsync

Suppress

Comment on lines +195 to +227
private static void Execute(object? state)
{
// .NET Standard doesn't support if(state is (IAmACommandProcessor, FireSchedulerMessage))
var fireMessage = state as (IAmACommandProcessor, FireSchedulerMessage)?;
if (fireMessage != null)
{
var (processor, message) = (fireMessage.Value.Item1, fireMessage.Value.Item2);
BrighterAsyncContext.Run(async () => await processor.SendAsync(message));

if (s_timers.TryRemove(message.Id, out var timer))
{
timer.Dispose();
}

return;
}

var fireRequest = state as (IAmACommandProcessor, FireSchedulerRequest)?;
if (fireRequest != null)
{
var (processor, request) = (fireRequest.Value.Item1, fireRequest.Value.Item2);
BrighterAsyncContext.Run(async () => await processor.SendAsync(request));

if (s_timers.TryRemove(request.Id, out var timer))
{
timer.Dispose();
}

return;
}

Logger.LogError("Invalid input during executing scheduler {Data}", state);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ New issue: Bumpy Road Ahead
Execute has 2 blocks with nested conditional logic. Any nesting of 2 or deeper is considered. Threshold is one single, nested block per function

Suppress

Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Health Improved (1 files improve in Code Health)

Gates Failed
Prevent hotspot decline (5 hotspots with Code Duplication, Complex Method, Large Method)
Enforce critical code health rules (2 files with Bumpy Road Ahead)
Enforce advisory code health rules (11 files with Code Duplication, Complex Method, Large Method, Excess Number of Function Arguments)

Gates Passed
1 Quality Gates Passed

See analysis details in CodeScene

Reason for failure
Prevent hotspot decline Violations Code Health Impact
CommandProcessor.cs 1 rule in this hotspot 8.28 → 7.33 Suppress
RmqMessageProducer.cs 1 rule in this hotspot 9.39 → 9.10 Suppress
OutboxProducerMediator.cs 1 rule in this hotspot 7.38 → 7.16 Suppress
ControlBusReceiverBuilder.cs 1 rule in this hotspot 8.46 → 8.46 Suppress
ServiceCollectionExtensions.cs 1 rule in this hotspot 8.56 → 9.06 Suppress
Enforce critical code health rules Violations Code Health Impact
InMemoryScheduler.cs 1 critical rule 10.00 → 9.24 Suppress
FireSchedulerRequestHandler.cs 1 critical rule 10.00 → 9.39 Suppress
Enforce advisory code health rules Violations Code Health Impact
CommandProcessor.cs 1 advisory rule 8.28 → 7.33 Suppress
InMemoryScheduler.cs 1 advisory rule 10.00 → 9.24 Suppress
MsSqlMessageProducer.cs 1 advisory rule 10.00 → 9.39 Suppress
QuartzScheduler.cs 1 advisory rule 10.00 → 9.39 Suppress
AwsScheduler.cs 1 advisory rule 10.00 → 9.69 Suppress
KafkaMessageProducer.cs 1 advisory rule 9.39 → 9.10 Suppress
RmqMessageProducer.cs 1 advisory rule 9.39 → 9.10 Suppress
OutboxProducerMediator.cs 1 advisory rule 7.38 → 7.16 Suppress
BrighterSpanExtensions.cs 1 advisory rule 9.50 → 9.47 Suppress
ControlBusReceiverBuilder.cs 1 advisory rule 8.46 → 8.46 Suppress
ServiceCollectionExtensions.cs 1 advisory rule 8.56 → 9.06 Suppress
View Improvements
File Code Health Impact Categories Improved
ServiceCollectionExtensions.cs 8.56 → 9.06 Code Duplication
KafkaMessageProducer.cs 9.39 → 9.10 Code Duplication
RedisMessageProducer.cs no change Code Duplication

Quality Gate Profile: Clean Code Collective
Want more control? Customize Code Health rules or catch issues early with our IDE extension and CLI tool.

Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Health Improved (1 files improve in Code Health)

Gates Failed
Prevent hotspot decline (4 hotspots with Code Duplication, Complex Method, Large Method)
Enforce critical code health rules (2 files with Bumpy Road Ahead)
Enforce advisory code health rules (10 files with Code Duplication, Complex Method, Large Method, Excess Number of Function Arguments)

Gates Passed
1 Quality Gates Passed

See analysis details in CodeScene

Reason for failure
Prevent hotspot decline Violations Code Health Impact
CommandProcessor.cs 1 rule in this hotspot 8.28 → 7.33 Suppress
OutboxProducerMediator.cs 1 rule in this hotspot 7.38 → 7.16 Suppress
ControlBusReceiverBuilder.cs 1 rule in this hotspot 8.46 → 8.46 Suppress
ServiceCollectionExtensions.cs 1 rule in this hotspot 8.56 → 9.06 Suppress
Enforce critical code health rules Violations Code Health Impact
InMemoryScheduler.cs 1 critical rule 10.00 → 9.24 Suppress
FireSchedulerRequestHandler.cs 1 critical rule 10.00 → 9.39 Suppress
Enforce advisory code health rules Violations Code Health Impact
CommandProcessor.cs 1 advisory rule 8.28 → 7.33 Suppress
InMemoryScheduler.cs 1 advisory rule 10.00 → 9.24 Suppress
MsSqlMessageProducer.cs 1 advisory rule 10.00 → 9.39 Suppress
QuartzScheduler.cs 1 advisory rule 10.00 → 9.39 Suppress
AwsScheduler.cs 1 advisory rule 10.00 → 9.69 Suppress
KafkaMessageProducer.cs 1 advisory rule 9.39 → 9.10 Suppress
OutboxProducerMediator.cs 1 advisory rule 7.38 → 7.16 Suppress
BrighterSpanExtensions.cs 1 advisory rule 9.50 → 9.47 Suppress
ControlBusReceiverBuilder.cs 1 advisory rule 8.46 → 8.46 Suppress
ServiceCollectionExtensions.cs 1 advisory rule 8.56 → 9.06 Suppress
View Improvements
File Code Health Impact Categories Improved
ServiceCollectionExtensions.cs 8.56 → 9.06 Code Duplication
KafkaMessageProducer.cs 9.39 → 9.10 Code Duplication
RedisMessageProducer.cs no change Code Duplication

Quality Gate Profile: Clean Code Collective
Want more control? Customize Code Health rules or catch issues early with our IDE extension and CLI tool.

Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Health Improved (1 files improve in Code Health)

Gates Failed
Prevent hotspot decline (4 hotspots with Code Duplication, Complex Method, Large Method)
Enforce critical code health rules (2 files with Bumpy Road Ahead)
Enforce advisory code health rules (12 files with Code Duplication, Complex Method, Large Method, Excess Number of Function Arguments, Complex Conditional)

Gates Passed
1 Quality Gates Passed

See analysis details in CodeScene

Reason for failure
Prevent hotspot decline Violations Code Health Impact
CommandProcessor.cs 1 rule in this hotspot 8.28 → 7.33 Suppress
OutboxProducerMediator.cs 1 rule in this hotspot 7.38 → 7.16 Suppress
ControlBusReceiverBuilder.cs 1 rule in this hotspot 8.46 → 8.46 Suppress
ServiceCollectionExtensions.cs 1 rule in this hotspot 8.56 → 9.06 Suppress
Enforce critical code health rules Violations Code Health Impact
InMemoryScheduler.cs 1 critical rule 10.00 → 9.24 Suppress
FireSchedulerRequestHandler.cs 1 critical rule 10.00 → 9.39 Suppress
Enforce advisory code health rules Violations Code Health Impact
CommandProcessor.cs 1 advisory rule 8.28 → 7.33 Suppress
InMemoryScheduler.cs 1 advisory rule 10.00 → 9.24 Suppress
MsSqlMessageProducer.cs 1 advisory rule 10.00 → 9.39 Suppress
QuartzScheduler.cs 1 advisory rule 10.00 → 9.39 Suppress
RmqMessageProducer.cs 2 advisory rules 9.39 → 8.82 Suppress
AwsScheduler.cs 1 advisory rule 10.00 → 9.69 Suppress
RmqMessageProducer.cs 1 advisory rule 9.69 → 9.39 Suppress
KafkaMessageProducer.cs 1 advisory rule 9.39 → 9.10 Suppress
OutboxProducerMediator.cs 1 advisory rule 7.38 → 7.16 Suppress
BrighterSpanExtensions.cs 1 advisory rule 9.50 → 9.47 Suppress
ControlBusReceiverBuilder.cs 1 advisory rule 8.46 → 8.46 Suppress
ServiceCollectionExtensions.cs 1 advisory rule 8.56 → 9.06 Suppress
View Improvements
File Code Health Impact Categories Improved
ServiceCollectionExtensions.cs 8.56 → 9.06 Code Duplication
KafkaMessageProducer.cs 9.39 → 9.10 Code Duplication
RedisMessageProducer.cs no change Code Duplication

Quality Gate Profile: Clean Code Collective
Want more control? Customize Code Health rules or catch issues early with our IDE extension and CLI tool.

Comment on lines +58 to +86
private async Task ExecuteAsync<T>(FireSchedulerRequest command, CancellationToken cancellationToken = default)
where T : class, IRequest
{
var request = JsonSerializer.Deserialize<T>(command.RequestData, JsonSerialisationOptions.Options)!;
if (command is { SchedulerType: RequestSchedulerType.Send, Async: true })
{
await processor.SendAsync(request, cancellationToken: cancellationToken);
}
else if (command.SchedulerType == RequestSchedulerType.Send)
{
processor.Send(request);
}
else if (command is { SchedulerType: RequestSchedulerType.Publish, Async: true })
{
await processor.PublishAsync(request, cancellationToken: cancellationToken);
}
else if (command.SchedulerType == RequestSchedulerType.Publish)
{
processor.Publish(request);
}
else if (command is { SchedulerType: RequestSchedulerType.Post, Async: true })
{
await processor.PostAsync(request, cancellationToken: cancellationToken);
}
else if (command.SchedulerType == RequestSchedulerType.Post)
{
processor.Post(request);
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ New issue: Bumpy Road Ahead
ExecuteAsync has 5 blocks with nested conditional logic. Any nesting of 2 or deeper is considered. Threshold is one single, nested block per function

Suppress

Comment on lines +38 to +58
public string Schedule(Message message, TimeSpan delay)
{
var id = getOrCreateMessageSchedulerId(message);
if (s_timers.TryGetValue(id, out var timer))
{
if (onConflict == OnSchedulerConflict.Throw)
{
throw new InvalidOperationException($"scheduler with '{id}' id already exists");
}

timer.Dispose();
}

s_timers[id] = timeProvider.CreateTimer(Execute, (processor, new FireSchedulerMessage
{
Id = id,
Async = false,
Message = message
}), delay, TimeSpan.Zero);
return id;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ New issue: Code Duplication
The module contains 4 functions with similar structure: Schedule,Schedule,ScheduleAsync,ScheduleAsync

Suppress

Task.Delay(delay.Value).Wait();
rmqMessagePublisher.PublishMessage(message, TimeSpan.Zero);
}
if (delay == TimeSpan.Zero || DelaySupported || Scheduler == null)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ New issue: Complex Conditional
SendWithDelay has 1 complex conditionals with 2 branches, threshold = 2

Suppress

public async Task SendWithDelayAsync(Message message, TimeSpan? delay, CancellationToken cancellationToken = default)
=> await SendWithDelayAsync(message, delay, true, cancellationToken);

private async Task SendWithDelayAsync(Message message, TimeSpan? delay, bool useSchedulerAsync, CancellationToken cancellationToken = default)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ New issue: Complex Method
SendWithDelayAsync has a cyclomatic complexity of 10, threshold = 9

Suppress

@@ -144,14 +153,19 @@ public async Task SendWithDelayAsync(Message message, TimeSpan? delay, Cancellat

_pendingConfirmations.TryAdd(await Channel.GetNextPublishSequenceNumberAsync(cancellationToken), message.Id);

if (DelaySupported)
if (delay == TimeSpan.Zero || DelaySupported || Scheduler == null)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ New issue: Complex Conditional
SendWithDelayAsync has 1 complex conditionals with 2 branches, threshold = 2

Suppress

Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Health Improved (1 files improve in Code Health)

Gates Failed
Prevent hotspot decline (3 hotspots with Code Duplication, Large Method)
Enforce critical code health rules (2 files with Bumpy Road Ahead)
Enforce advisory code health rules (11 files with Code Duplication, Large Method, Complex Method, Excess Number of Function Arguments, Complex Conditional)

Gates Passed
1 Quality Gates Passed

See analysis details in CodeScene

Reason for failure
Prevent hotspot decline Violations Code Health Impact
CommandProcessor.cs 1 rule in this hotspot 8.28 → 7.33 Suppress
OutboxProducerMediator.cs 1 rule in this hotspot 7.38 → 7.16 Suppress
ControlBusReceiverBuilder.cs 1 rule in this hotspot 8.46 → 8.46 Suppress
Enforce critical code health rules Violations Code Health Impact
InMemoryScheduler.cs 1 critical rule 10.00 → 9.24 Suppress
FireSchedulerRequestHandler.cs 1 critical rule 10.00 → 9.39 Suppress
Enforce advisory code health rules Violations Code Health Impact
CommandProcessor.cs 1 advisory rule 8.28 → 7.33 Suppress
InMemoryScheduler.cs 1 advisory rule 10.00 → 9.24 Suppress
MsSqlMessageProducer.cs 1 advisory rule 10.00 → 9.39 Suppress
QuartzScheduler.cs 1 advisory rule 10.00 → 9.39 Suppress
RmqMessageProducer.cs 2 advisory rules 9.39 → 8.82 Suppress
AwsScheduler.cs 1 advisory rule 10.00 → 9.69 Suppress
RmqMessageProducer.cs 1 advisory rule 9.69 → 9.39 Suppress
KafkaMessageProducer.cs 1 advisory rule 9.39 → 9.10 Suppress
OutboxProducerMediator.cs 1 advisory rule 7.38 → 7.16 Suppress
BrighterSpanExtensions.cs 1 advisory rule 9.50 → 9.47 Suppress
ControlBusReceiverBuilder.cs 1 advisory rule 8.46 → 8.46 Suppress
View Improvements
File Code Health Impact Categories Improved
ServiceCollectionExtensions.cs 8.56 → 9.11 Code Duplication
KafkaMessageProducer.cs 9.39 → 9.10 Code Duplication
RedisMessageProducer.cs no change Code Duplication

Quality Gate Profile: Clean Code Collective
Want more control? Customize Code Health rules or catch issues early with our IDE extension and CLI tool.

@lillo42 lillo42 marked this pull request as ready for review February 17, 2025 15:29
Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Health Improved (1 files improve in Code Health)

Gates Failed
Prevent hotspot decline (3 hotspots with Code Duplication, Large Method)
Enforce critical code health rules (2 files with Bumpy Road Ahead)
Enforce advisory code health rules (12 files with Code Duplication, Large Method, Complex Method, Excess Number of Function Arguments, Complex Conditional)

Gates Passed
1 Quality Gates Passed

See analysis details in CodeScene

Reason for failure
Prevent hotspot decline Violations Code Health Impact
CommandProcessor.cs 1 rule in this hotspot 8.28 → 7.33 Suppress
OutboxProducerMediator.cs 1 rule in this hotspot 7.38 → 7.16 Suppress
ControlBusReceiverBuilder.cs 1 rule in this hotspot 8.46 → 8.46 Suppress
Enforce critical code health rules Violations Code Health Impact
InMemoryScheduler.cs 1 critical rule 10.00 → 9.24 Suppress
FireSchedulerRequestHandler.cs 1 critical rule 10.00 → 9.39 Suppress
Enforce advisory code health rules Violations Code Health Impact
CommandProcessor.cs 1 advisory rule 8.28 → 7.33 Suppress
InMemoryScheduler.cs 1 advisory rule 10.00 → 9.24 Suppress
MsSqlMessageProducer.cs 1 advisory rule 10.00 → 9.39 Suppress
QuartzScheduler.cs 1 advisory rule 10.00 → 9.39 Suppress
AzureServiceBusScheduler.cs 1 advisory rule 10.00 → 9.39 Suppress
RmqMessageProducer.cs 2 advisory rules 9.39 → 8.82 Suppress
AwsScheduler.cs 1 advisory rule 10.00 → 9.69 Suppress
RmqMessageProducer.cs 1 advisory rule 9.69 → 9.39 Suppress
KafkaMessageProducer.cs 1 advisory rule 9.39 → 9.10 Suppress
OutboxProducerMediator.cs 1 advisory rule 7.38 → 7.16 Suppress
BrighterSpanExtensions.cs 1 advisory rule 9.50 → 9.47 Suppress
ControlBusReceiverBuilder.cs 1 advisory rule 8.46 → 8.46 Suppress
View Improvements
File Code Health Impact Categories Improved
ServiceCollectionExtensions.cs 8.56 → 9.11 Code Duplication
KafkaMessageProducer.cs 9.39 → 9.10 Code Duplication
RedisMessageProducer.cs no change Code Duplication

Quality Gate Profile: Clean Code Collective
Want more control? Customize Code Health rules or catch issues early with our IDE extension and CLI tool.

Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Health Improved (1 files improve in Code Health)

Gates Failed
Prevent hotspot decline (3 hotspots with Code Duplication, Large Method)
Enforce critical code health rules (2 files with Bumpy Road Ahead)
Enforce advisory code health rules (12 files with Code Duplication, Large Method, Complex Method, Excess Number of Function Arguments, Complex Conditional)

Gates Passed
1 Quality Gates Passed

See analysis details in CodeScene

Reason for failure
Prevent hotspot decline Violations Code Health Impact
CommandProcessor.cs 1 rule in this hotspot 8.28 → 7.33 Suppress
OutboxProducerMediator.cs 1 rule in this hotspot 7.38 → 7.16 Suppress
ControlBusReceiverBuilder.cs 1 rule in this hotspot 8.46 → 8.46 Suppress
Enforce critical code health rules Violations Code Health Impact
InMemoryScheduler.cs 1 critical rule 10.00 → 9.24 Suppress
FireSchedulerRequestHandler.cs 1 critical rule 10.00 → 9.39 Suppress
Enforce advisory code health rules Violations Code Health Impact
CommandProcessor.cs 1 advisory rule 8.28 → 7.33 Suppress
InMemoryScheduler.cs 1 advisory rule 10.00 → 9.24 Suppress
MsSqlMessageProducer.cs 1 advisory rule 10.00 → 9.39 Suppress
QuartzScheduler.cs 1 advisory rule 10.00 → 9.39 Suppress
AzureServiceBusScheduler.cs 1 advisory rule 10.00 → 9.39 Suppress
RmqMessageProducer.cs 2 advisory rules 9.39 → 8.82 Suppress
AwsScheduler.cs 1 advisory rule 10.00 → 9.69 Suppress
RmqMessageProducer.cs 1 advisory rule 9.69 → 9.39 Suppress
KafkaMessageProducer.cs 1 advisory rule 9.39 → 9.10 Suppress
OutboxProducerMediator.cs 1 advisory rule 7.38 → 7.16 Suppress
BrighterSpanExtensions.cs 1 advisory rule 9.50 → 9.47 Suppress
ControlBusReceiverBuilder.cs 1 advisory rule 8.46 → 8.46 Suppress
View Improvements
File Code Health Impact Categories Improved
ServiceCollectionExtensions.cs 8.56 → 9.11 Code Duplication
KafkaMessageProducer.cs 9.39 → 9.10 Code Duplication
RedisMessageProducer.cs no change Code Duplication

Quality Gate Profile: Clean Code Collective
Want more control? Customize Code Health rules or catch issues early with our IDE extension and CLI tool.

Comment on lines +24 to +39
public async Task<string> ScheduleAsync(Message message, DateTimeOffset at,
CancellationToken cancellationToken = default)
{
var seq = await sender.ScheduleMessageAsync(
ConvertToServiceBusMessage(new Message
{
Header =
new MessageHeader(message.Id, schedulerTopic, MessageType.MT_EVENT,
subject: nameof(FireAzureScheduler)),
Body = new MessageBody(JsonSerializer.Serialize(
new FireAzureScheduler { Id = message.Id, Async = true, Message = message },
JsonSerialisationOptions.Options))
}), at, cancellationToken);

return seq.ToString();
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ New issue: Code Duplication
The module contains 4 functions with similar structure: Schedule,Schedule,ScheduleAsync,ScheduleAsync

Suppress

Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Health Improved (1 files improve in Code Health)

Gates Failed
Prevent hotspot decline (3 hotspots with Code Duplication, Large Method)
Enforce critical code health rules (2 files with Bumpy Road Ahead)
Enforce advisory code health rules (12 files with Code Duplication, Large Method, Complex Method, Excess Number of Function Arguments, Complex Conditional)

Gates Passed
1 Quality Gates Passed

See analysis details in CodeScene

Reason for failure
Prevent hotspot decline Violations Code Health Impact
CommandProcessor.cs 1 rule in this hotspot 8.28 → 7.33 Suppress
OutboxProducerMediator.cs 1 rule in this hotspot 7.38 → 7.16 Suppress
ControlBusReceiverBuilder.cs 1 rule in this hotspot 8.46 → 8.46 Suppress
Enforce critical code health rules Violations Code Health Impact
InMemoryScheduler.cs 1 critical rule 10.00 → 9.24 Suppress
FireSchedulerRequestHandler.cs 1 critical rule 10.00 → 9.39 Suppress
Enforce advisory code health rules Violations Code Health Impact
CommandProcessor.cs 1 advisory rule 8.28 → 7.33 Suppress
InMemoryScheduler.cs 1 advisory rule 10.00 → 9.24 Suppress
MsSqlMessageProducer.cs 1 advisory rule 10.00 → 9.39 Suppress
QuartzScheduler.cs 1 advisory rule 10.00 → 9.39 Suppress
AzureServiceBusScheduler.cs 1 advisory rule 10.00 → 9.39 Suppress
RmqMessageProducer.cs 2 advisory rules 9.39 → 8.82 Suppress
AwsScheduler.cs 1 advisory rule 10.00 → 9.69 Suppress
RmqMessageProducer.cs 1 advisory rule 9.69 → 9.39 Suppress
KafkaMessageProducer.cs 1 advisory rule 9.39 → 9.10 Suppress
OutboxProducerMediator.cs 1 advisory rule 7.38 → 7.16 Suppress
BrighterSpanExtensions.cs 1 advisory rule 9.50 → 9.47 Suppress
ControlBusReceiverBuilder.cs 1 advisory rule 8.46 → 8.46 Suppress
View Improvements
File Code Health Impact Categories Improved
ServiceCollectionExtensions.cs 8.56 → 9.11 Code Duplication
KafkaMessageProducer.cs 9.39 → 9.10 Code Duplication
RedisMessageProducer.cs no change Code Duplication

Quality Gate Profile: Clean Code Collective
Want more control? Customize Code Health rules or catch issues early with our IDE extension and CLI tool.

Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Health Improved (1 files improve in Code Health)

Gates Failed
Prevent hotspot decline (3 hotspots with Code Duplication, Large Method)
Enforce critical code health rules (2 files with Bumpy Road Ahead)
Enforce advisory code health rules (12 files with Code Duplication, Large Method, Complex Method, Excess Number of Function Arguments, Complex Conditional)

Gates Passed
1 Quality Gates Passed

See analysis details in CodeScene

Reason for failure
Prevent hotspot decline Violations Code Health Impact
CommandProcessor.cs 1 rule in this hotspot 8.28 → 7.33 Suppress
OutboxProducerMediator.cs 1 rule in this hotspot 7.38 → 7.16 Suppress
ControlBusReceiverBuilder.cs 1 rule in this hotspot 8.46 → 8.46 Suppress
Enforce critical code health rules Violations Code Health Impact
InMemoryScheduler.cs 1 critical rule 10.00 → 9.24 Suppress
FireSchedulerRequestHandler.cs 1 critical rule 10.00 → 9.39 Suppress
Enforce advisory code health rules Violations Code Health Impact
CommandProcessor.cs 1 advisory rule 8.28 → 7.33 Suppress
InMemoryScheduler.cs 1 advisory rule 10.00 → 9.24 Suppress
MsSqlMessageProducer.cs 1 advisory rule 10.00 → 9.39 Suppress
QuartzScheduler.cs 1 advisory rule 10.00 → 9.39 Suppress
AzureServiceBusScheduler.cs 1 advisory rule 10.00 → 9.39 Suppress
RmqMessageProducer.cs 2 advisory rules 9.39 → 8.82 Suppress
AwsScheduler.cs 1 advisory rule 10.00 → 9.69 Suppress
RmqMessageProducer.cs 1 advisory rule 9.69 → 9.39 Suppress
KafkaMessageProducer.cs 1 advisory rule 9.39 → 9.10 Suppress
OutboxProducerMediator.cs 1 advisory rule 7.38 → 7.16 Suppress
BrighterSpanExtensions.cs 1 advisory rule 9.50 → 9.47 Suppress
ControlBusReceiverBuilder.cs 1 advisory rule 8.46 → 8.46 Suppress
View Improvements
File Code Health Impact Categories Improved
ServiceCollectionExtensions.cs 8.56 → 9.11 Code Duplication
KafkaMessageProducer.cs 9.39 → 9.10 Code Duplication
RedisMessageProducer.cs no change Code Duplication

Quality Gate Profile: Clean Code Collective
Want more control? Customize Code Health rules or catch issues early with our IDE extension and CLI tool.

@iancooper
Copy link
Member

  • Thanks for getting spans in; that really helps!!
  • Thanks for adding the overloads with the offset; having both at and delay overloads makes sense
  • Generally, all public methods should have XML comments. Feel free to make classes internal, where they are not exposed (for consumption or tests). You can use to indicate types in params and return values; use remarks if there is something interesting. We may document an implementation if it has details that are class-specific, not interface-specific.
  • Let's chat about the design decision to have a FireScheduleRequest being Sent to the CP and then the correct CP method being invoked in the hand. You might be trying to align the message and request call-back paths. I guess the trade-off is between one pattern, and a cheaper request implementation. Might be worth updating our ADR for why.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 - In Progress Draft This is a work in progress feature request grabbed by assignee .NET Pull requests that update .net code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants