nats-io / nats.net.v1

The official C# Client for NATS
Apache License 2.0
645 stars 153 forks source link

Can't create a source without it being an external source #662

Closed Lemorz56 closed 2 years ago

Lemorz56 commented 2 years ago

Defect

Make sure that these boxes are checked before submitting your issue -- thank you!

Versions of NATS.Client and nats-server:

var cf = new ConnectionFactory(); var con = cf.CreateConnection("nats://localhost:4223");

var jsm = con.CreateJetStreamManagementContext();

var streamBuilder = new StreamConfiguration.StreamConfigurationBuilder(); var streamBuilderTwo = new StreamConfiguration.StreamConfigurationBuilder();

var streamOne = streamBuilder .WithName("test") .WithSubjects(new string[] { "test.sub" }) .Build();

var sourceTest = new Source.SourceBuilder() .WithName("test") .WithFilterSubject("test.*") .WithStartSeq(0) .WithStartTime(DateTime.MinValue) .Build();

var streamTwoWithSource = streamBuilderTwo .WithName("archive") .WithSources(new Source[] { sourceTest }) .Build();

jsm.AddStream(streamOne); jsm.AddStream(streamTwoWithSource);

causes a null reference error when adding the said stream with the sources with IJetstreamManagement.AddStream method.
`Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
   at NATS.Client.JetStream.Source.ToJsonNode()
   at NATS.Client.JetStream.StreamConfiguration.ToJsonNode()
   at NATS.Client.JetStream.JsonSerializable.Serialize()
   at NATS.Client.JetStream.JetStreamManagement.AddOrUpdateStream(StreamConfiguration config, String addUpdateTemplate)
   at NATS.Client.JetStream.JetStreamManagement.AddStream(StreamConfiguration config)`

This forces me to supply WithExternal even if the source is not external. Tried these two ways without any success as it still becomes an external source and wont function properly. However the stream does get created.
`.WithExternal(new External("", ""))` and `.WithExternal(new External(null, null))`

#### Expected result:
If the expected result would follow the same behavior as for example Stream Configuration builder, the expected result should create a stream, even if WithExternal is not supplied, and result in a similar output (**sources is the only important sections in this context**) when running for example, `nats stream info --json`.

```json
{
  "config": {
    "name": "archive",
    "retention": "limits",
    "max_consumers": -1,
    "max_msgs_per_subject": -1,
    "max_msgs": -1,
    "max_bytes": -1,
    "max_age": 0,
    "max_msg_size": -1,
    "storage": "file",
    "discard": "old",
    "num_replicas": 1,
    "duplicate_window": 120000000000,
    "sources": [
        {
            "name": "test",
            "filter_subject": "test.*"
        }
    ],
    "sealed": false,
    "deny_delete": false,
    "deny_purge": false,
    "allow_rollup_hdrs": false
},
  "created": "2022-08-26T11:16:56.9712292Z",
  "state": {
    "messages": 0,
    "bytes": 0,
    "first_seq": 0,
    "first_ts": "0001-01-01T00:00:00Z",
    "last_seq": 0,
    "last_ts": "0001-01-01T00:00:00Z",
    "consumer_count": 0
  },
  "sources": [
    {
      "name": "test",
      "lag": 0,
      "active": 0
    }
  ]
}

Actual result:

When using nats.net user is forced to supply all properties including external, leaving the user with no way to create a source without the external property.

Supplying .WithExternal(new External("", "")) or .WithExternal(new External(null, null)) instead creates a stream without a working source that makes the nats stream info --json look like this:

{
  "config": {
    "name": "archive",
    "retention": "limits",
    "max_consumers": -1,
    "max_msgs_per_subject": -1,
    "max_msgs": -1,
    "max_bytes": -1,
    "max_age": 0,
    "max_msg_size": -1,
    "storage": "file",
    "discard": "old",
    "num_replicas": 1,
    "duplicate_window": 120000000000,
    "sources": [
      {
        "name": "test",
        "filter_subject": "test.*",
        "external": {
          "api": "",
          "deliver": ""
        }
      }
    ],
    "sealed": false,
    "deny_delete": false,
    "deny_purge": false,
    "allow_rollup_hdrs": false
  },
  "created": "2022-08-26T11:16:56.9712292Z",
  "state": {
    "messages": 0,
    "bytes": 0,
    "first_seq": 0,
    "first_ts": "0001-01-01T00:00:00Z",
    "last_seq": 0,
    "last_ts": "0001-01-01T00:00:00Z",
    "consumer_count": 0
  },
  "sources": [
    {
      "name": "test",
      "external": {
        "api": "",
        "deliver": ""
      },
      "lag": 0,
      "active": -1
    }
  ]
}

This means there is no way for me to create a working source without it being external? Maybe I'm just using it in a wrong way.

scottf commented 2 years ago

Thank you for the complete bug report, this is just a bug, you are using it correct. I fixed it here, https://github.com/nats-io/nats.net/pull/663 and checked the external object before trying to add it to the json. I will make a pre-release as soon as this is merged since I don't want to do a full release until I finish something else I'm working on, but it should only be a few more days.

scottf commented 2 years ago

This fix is available in a pre-release. https://www.nuget.org/packages/NATS.Client/0.14.9-pre3

Lemorz56 commented 2 years ago

This fix is available in a pre-release. https://www.nuget.org/packages/NATS.Client/0.14.9-pre3

Thanks a lot for your quick reply and your fix 👍🏼.