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
Implement Consumers Pause #432
Conversation
Signed-off-by: Maurice van Veen <github@mauricevanveen.com>
@@ -335,3 +337,30 @@ public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, Jso | |||
public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options) => | |||
writer.WriteNumberValue((long)(value.TotalMilliseconds * 1_000_000L)); | |||
} | |||
|
|||
internal class NatsJSJsonNullableNanosecondsConverter : JsonConverter<TimeSpan?> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have created this to support a nullable TimeSpan?
when used for the PauseRemaining
in the ConsumerInfo
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, added a test for PauseRemaining
.
Signed-off-by: Maurice van Veen <github@mauricevanveen.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some suggestions around immutability and return types implementation.
{ | ||
[System.Text.Json.Serialization.JsonPropertyName("paused")] | ||
[System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.Never)] | ||
public bool Paused { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As this is a server response, I'd imagine this should be exposed as an immutable type ( see https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/immutability ) -- in short, the properties should be { get; init; }
to allow the JSON serializer to function correctly while preventing the caller from changing the properties (or more to the point, believing that changing them may have some kind of effect.) With this mind, the Paused
property should be named IsPaused
to align better with convention
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(The same should apply for other immutable return values here)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we make this change in others? (not in this PR of course)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have renamed to IsPaused
, as well as using the { get; init; }
in the ConsumerPauseResponse
.
Think it makes sense to have other server responses (as well as ConsumerInfo
for example) use the same { get; init; }
.
But indeed like @mtmk says, would agree that would be good for another PR 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@oising, it looks like init
isn't supported in generated serializers in net6:
System.InvalidOperationException : Deserialization of init-only properties is currently not supported in source generation mode.
we either ifdef or wait until net6 eol
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious about something -- following the thread here ( dotnet/runtime#58770 ), that leads to the net7 PR here ( dotnet/runtime#68064 ) -- that seems to say that switching to a positional syntax for the record, i.e. public record Foo (bool Foo, string Bar);
also emits init only properties, but the source generated code for a net6 target will work fine (because it generates a call to a constructor and doesn't try to manipulate the setters directly), as long as you compile with an SDK greater than 6 (i.e. sdk 7 or 8 .) It seems that full support for init/required properties arrived in dotnet/runtime#79828 and this only works for net8 targets. So, switching to position syntax for the record may work for net6 targets, if we compile with SDK8
(edit: I'll test this hypothesis and post back here)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I remember now that "for reasons" you guys cannot down-target net6 using the net8 SDK because of how it pulls in dependencies and they will clash with other things. It actually works fine for net6 targeting with SDK8, using both syntaxes (init-only or positional), and works only with positional with SDK7. For SDK6, it's broken as you state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested with the SDK8 before I remembered the limitation:
// See https://aka.ms/new-console-template for more information
// Define the record type Foo
using System.Text.Json;
using System.Text.Json.Serialization;
// Create an instance of Foo
FooPos foo1 = new FooPos(true, "Test");
FooProp foo2 = new FooProp()
{
BoolValue = true,
StringValue = "Test"
};
// Create an instance of the context
var context = new MyJsonContext();
// Serialize the Foo instance to JSON using the context
string json = JsonSerializer.Serialize(foo1, context.FooPos);
Console.WriteLine($"Serialized FooPos: {json}");
var foo3 = JsonSerializer.Deserialize<FooPos>(json, context.FooPos);
Console.WriteLine($"Deserialized FooPos: {foo3}");
json = JsonSerializer.Serialize(foo2, context.FooProp);
Console.WriteLine($"Serialized FooProp: {json}");
var foo4 = JsonSerializer.Deserialize<FooProp>(json, context.FooProp);
Console.WriteLine($"Deserialized FooProp: {foo4}");
public record FooPos(bool BoolValue, string StringValue);
public record FooProp
{
public bool BoolValue { get; init; }
public string? StringValue { get; init; }
}
// Define the context class for JSON serialization
[JsonSourceGenerationOptions(
WriteIndented = true,
GenerationMode = JsonSourceGenerationMode.Metadata)]
[JsonSerializable(typeof(FooPos))]
[JsonSerializable(typeof(FooProp))]
public partial class MyJsonContext : JsonSerializerContext
{
}
Works fine under SDK8 :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I guess just either ifdef, or defer the work until later - but it would be nice to start on the True Path now ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice work 💯 🚀 ifdef'ed it ;-) We should be good. Created an issue so we don't forget #435
Signed-off-by: Maurice van Veen <github@mauricevanveen.com>
Signed-off-by: Maurice van Veen <github@mauricevanveen.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM thanks @MauriceVanVeen 💯 🥇
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Resolves #416
Adds support for pausing and resuming consumers.
NatsJSContext.Consumers
now has methods toPauseConsumerAsync(stream, consumer, pauseUntil)
, as well asResumeConsumerAsync(stream, consumer)
.ConsumerConfiguration
now has support for settingPauseUntil
as well. Allowing to set it during consumer creation.The implementation is similar to and based on the changes I made for the Java client: nats-io/nats.java#1093
Am not too familiar with .NET, and this is the first time contributing to this client. Please let me know if I'm missing any things specific to .NET or this client, that can be improved further.