public void TestOrderedConsumerAsync() { Console.SetOut(new ConsoleWriter(output)); Context.RunInJsServer(c => { // Setup IJetStream js = c.CreateJetStreamContext(); string subject = Subject(222); CreateMemoryStream(c, Stream(222), subject); // Get this in place before any subscriptions are made JetStream.PushMessageManagerFactoryImpl = (conn, so, cc, queueMode, syncMode) => new OrderedTestDropSimulator(conn, so, cc, queueMode, syncMode); // The options will be used in various ways PushSubscribeOptions pso = PushSubscribeOptions.Builder().WithOrdered(true).Build(); // Test queue exception void DummyTestHandler(object sender, MsgHandlerEventArgs args) { } NATSJetStreamClientException e = Assert.Throws <NATSJetStreamClientException>(() => js.PushSubscribeAsync(subject, QUEUE, DummyTestHandler, false, pso)); Assert.Contains(JsSubOrderedNotAllowOnQueues.Id, e.Message); // Setup async subscription CountdownEvent latch = new CountdownEvent(6); InterlockedInt received = new InterlockedInt(); InterlockedLong[] ssFlags = new InterlockedLong[6]; InterlockedLong[] csFlags = new InterlockedLong[6]; void TestHandler(object sender, MsgHandlerEventArgs args) { int i = received.Increment() - 1; ssFlags[i] = new InterlockedLong((long)args.msg.MetaData.StreamSequence); csFlags[i] = new InterlockedLong((long)args.msg.MetaData.ConsumerSequence); latch.Signal(); } js.PushSubscribeAsync(subject, TestHandler, false, pso); Thread.Sleep(1000); // Published messages will be intercepted by the OrderedTestDropSimulator JsPublish(js, subject, 101, 6); // wait for the messages latch.Wait(); // Loop through the messages to make sure I get stream sequence 1 to 6 ulong expectedStreamSeq = 1; while (expectedStreamSeq <= 6) { int idx = (int)expectedStreamSeq - 1; Assert.Equal(expectedStreamSeq, (ulong)ssFlags[idx].Read()); Assert.Equal(ExpectedConSeqNums[idx], (ulong)csFlags[idx].Read()); ++expectedStreamSeq; } }); }
public void TestQueueSubWorkflow() { Context.RunInJsServer(c => { // create the stream. CreateDefaultTestStream(c); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Setup the subscribers // - the PushSubscribeOptions can be re-used since all the subscribers are the same // - use a concurrent integer to track all the messages received // - have a list of subscribers and threads so I can track them PushSubscribeOptions pso = PushSubscribeOptions.Builder().WithDurable(DURABLE).Build(); InterlockedLong allReceived = new InterlockedLong(); IList <JsQueueSubscriber> subscribers = new List <JsQueueSubscriber>(); IList <Thread> subThreads = new List <Thread>(); for (int id = 1; id <= 3; id++) { // setup the subscription IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(SUBJECT, QUEUE, pso); // create and track the runnable JsQueueSubscriber qs = new JsQueueSubscriber(100, js, sub, allReceived); subscribers.Add(qs); // create, track and start the thread Thread t = new Thread(qs.Run); subThreads.Add(t); t.Start(); } c.Flush(DefaultTimeout); // flush outgoing communication with/to the server // create and start the publishing Thread pubThread = new Thread(new JsPublisher(js, 100).Run); pubThread.Start(); // wait for all threads to finish pubThread.Join(5000); foreach (Thread t in subThreads) { t.Join(5000); } ISet <string> uniqueDatas = new HashSet <string>(); // count int count = 0; foreach (JsQueueSubscriber qs in subscribers) { int r = qs.received; Assert.True(r > 0); count += r; foreach (string s in qs.datas) { Assert.True(uniqueDatas.Add(s)); } } Assert.Equal(100, count); }); }
public void TestDeliverSubjectValidation() { Assert.Null(PushSubscribeOptions.Builder() .WithDeliverSubject(null) .WithConfiguration(ConsumerConfiguration.Builder().WithDeliverSubject(null).Build()) .Build() .DeliverSubject); Assert.Equal("y", PushSubscribeOptions.Builder() .WithDeliverSubject(null) .WithConfiguration(ConsumerConfiguration.Builder().WithDeliverSubject("y").Build()) .Build() .DeliverSubject); Assert.Equal("x", PushSubscribeOptions.Builder() .WithDeliverSubject("x") .WithConfiguration(ConsumerConfiguration.Builder().WithDeliverSubject(null).Build()) .Build() .DeliverSubject); Assert.Equal("x", PushSubscribeOptions.Builder() .WithDeliverSubject("x") .WithConfiguration(ConsumerConfiguration.Builder().WithDeliverSubject("x").Build()) .Build() .DeliverSubject); Assert.Throws <NATSJetStreamClientException>(() => PushSubscribeOptions.Builder() .WithDeliverSubject("x") .WithConfiguration(ConsumerConfiguration.Builder().WithDeliverSubject("y").Build()) .Build()); }
private void ChangeExPush(IJetStream js, ConsumerConfiguration.ConsumerConfigurationBuilder builder, String changedField) { NATSJetStreamClientException e = Assert.Throws <NATSJetStreamClientException>( () => js.PushSubscribeSync(SUBJECT, PushSubscribeOptions.Builder().WithConfiguration(builder.Build()).Build())); _ChangeEx(e, changedField); }
public void TestDurableValidation() { // push Assert.Null(PushSubscribeOptions.Builder() .WithDurable(null) .WithConfiguration(ConsumerConfiguration.Builder().WithDurable(null).Build()) .Build() .Durable); Assert.Equal("y", PushSubscribeOptions.Builder() .WithDurable(null) .WithConfiguration(ConsumerConfiguration.Builder().WithDurable("y").Build()) .Build() .Durable); Assert.Equal("x", PushSubscribeOptions.Builder() .WithDurable("x") .WithConfiguration(ConsumerConfiguration.Builder().WithDurable(null).Build()) .Build() .Durable); Assert.Equal("x", PushSubscribeOptions.Builder() .WithDurable("x") .WithConfiguration(ConsumerConfiguration.Builder().WithDurable("x").Build()) .Build() .Durable); Assert.Throws <NATSJetStreamClientException>(() => PushSubscribeOptions.Builder() .WithDurable("x") .WithConfiguration(ConsumerConfiguration.Builder().WithDurable("y").Build()) .Build()); Assert.Null(PushSubscribeOptions.Builder().Build().Durable); // pull Assert.Equal("y", PullSubscribeOptions.Builder() .WithDurable(null) .WithConfiguration(ConsumerConfiguration.Builder().WithDurable("y").Build()) .Build() .Durable); Assert.Equal("x", PullSubscribeOptions.Builder() .WithDurable("x") .WithConfiguration(ConsumerConfiguration.Builder().WithDurable(null).Build()) .Build() .Durable); Assert.Equal("x", PullSubscribeOptions.Builder() .WithDurable("x") .WithConfiguration(ConsumerConfiguration.Builder().WithDurable("x").Build()) .Build() .Durable); Assert.Throws <NATSJetStreamClientException>(() => PullSubscribeOptions.Builder() .WithDurable("x") .WithConfiguration(ConsumerConfiguration.Builder().WithDurable("y").Build()) .Build()); }
public void TestPushSyncFlowControl() { InterlockedInt fcps = new InterlockedInt(); Action <Options> optionsModifier = opts => { opts.FlowControlProcessedEventHandler = (sender, args) => { fcps.Increment(); }; }; Context.RunInJsServer(new TestServerInfo(TestSeedPorts.AutoPort.Increment()), optionsModifier, c => { // create the stream. CreateDefaultTestStream(c); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); byte[] data = new byte[8192]; int MSG_COUNT = 1000; for (int x = 100_000; x < MSG_COUNT + 100_000; x++) { byte[] fill = Encoding.ASCII.GetBytes("" + x); Array.Copy(fill, 0, data, 0, 6); js.Publish(new Msg(SUBJECT, data)); } InterlockedInt count = new InterlockedInt(); HashSet <string> set = new HashSet <string>(); ConsumerConfiguration cc = ConsumerConfiguration.Builder().WithFlowControl(1000).Build(); PushSubscribeOptions pso = PushSubscribeOptions.Builder().WithConfiguration(cc).Build(); IJetStreamPushSyncSubscription ssub = js.PushSubscribeSync(SUBJECT, pso); for (int x = 0; x < MSG_COUNT; x++) { Msg msg = ssub.NextMessage(1000); byte[] fill = new byte[6]; Array.Copy(msg.Data, 0, fill, 0, 6); string id = Encoding.ASCII.GetString(fill); if (set.Add(id)) { count.Increment(); } msg.Ack(); } Assert.Equal(MSG_COUNT, count.Read()); Assert.True(fcps.Read() > 0); }); }
public void TestJetStreamPushEphemeral(string deliverSubject) { Context.RunInJsServer(c => { // create the stream. CreateDefaultTestStream(c); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // publish some messages JsPublish(js, SUBJECT, 1, 5); // Build our subscription options. PushSubscribeOptions options = PushSubscribeOptions.Builder() .WithDeliverSubject(deliverSubject) .Build(); // Subscription 1 IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(SUBJECT, options); AssertSubscription(sub, STREAM, null, deliverSubject, false); c.Flush(DefaultTimeout); // flush outgoing communication with/to the server IList <Msg> messages1 = ReadMessagesAck(sub); int total = messages1.Count; ValidateRedAndTotal(5, messages1.Count, 5, total); // read again, nothing should be there IList <Msg> messages0 = ReadMessagesAck(sub); total += messages0.Count; ValidateRedAndTotal(0, messages0.Count, 5, total); sub.Unsubscribe(); // Subscription 2 sub = js.PushSubscribeSync(SUBJECT, options); c.Flush(DefaultTimeout); // flush outgoing communication with/to the server // read what is available, same messages IList <Msg> messages2 = ReadMessagesAck(sub); total = messages2.Count; ValidateRedAndTotal(5, messages2.Count, 5, total); // read again, nothing should be there messages0 = ReadMessagesAck(sub); total += messages0.Count; ValidateRedAndTotal(0, messages0.Count, 5, total); AssertSameMessages(messages1, messages2); }); }
public void TestJetStreamSubscribeErrors() { Context.RunInJsServer(c => { IJetStream js = c.CreateJetStreamContext(); // stream not found PushSubscribeOptions psoInvalidStream = PushSubscribeOptions.Builder().WithStream(STREAM).Build(); Assert.Throws <NATSJetStreamException>(() => js.PushSubscribeSync(SUBJECT, psoInvalidStream)); void AssertThrowsForSubject(Func <object> testCode) { ArgumentException ae = Assert.Throws <ArgumentException>(testCode); Assert.StartsWith("Subject", ae.Message); } void AssertThrowsForQueue(Func <object> testCode) { ArgumentException ae = Assert.Throws <ArgumentException>(testCode); Assert.StartsWith("Queue", ae.Message); } void AssertThrowsForHandler(Func <object> testCode) { ArgumentNullException ae = Assert.Throws <ArgumentNullException>(testCode); Assert.Equal("Handler", ae.ParamName); } // subject AssertThrowsForSubject(() => js.PushSubscribeSync(HasSpace)); AssertThrowsForSubject(() => js.PushSubscribeSync(null, (PushSubscribeOptions)null)); AssertThrowsForSubject(() => js.PushSubscribeSync(HasSpace, Plain)); AssertThrowsForSubject(() => js.PushSubscribeSync(null, Plain, null)); AssertThrowsForSubject(() => js.PushSubscribeAsync(HasSpace, null, false)); AssertThrowsForSubject(() => js.PushSubscribeAsync(HasSpace, null, false, null)); AssertThrowsForSubject(() => js.PushSubscribeAsync(HasSpace, Plain, null, false)); AssertThrowsForSubject(() => js.PushSubscribeAsync(HasSpace, Plain, null, false, null)); // queue AssertThrowsForQueue(() => js.PushSubscribeSync(Plain, HasSpace)); AssertThrowsForQueue(() => js.PushSubscribeSync(Plain, HasSpace, null)); AssertThrowsForQueue(() => js.PushSubscribeAsync(Plain, HasSpace, null, false)); AssertThrowsForQueue(() => js.PushSubscribeAsync(Plain, HasSpace, null, false, null)); // handler AssertThrowsForHandler(() => js.PushSubscribeAsync(Plain, null, false)); AssertThrowsForHandler(() => js.PushSubscribeAsync(Plain, null, false, null)); AssertThrowsForHandler(() => js.PushSubscribeAsync(Plain, Plain, null, false)); AssertThrowsForHandler(() => js.PushSubscribeAsync(Plain, Plain, null, false, null)); }); }
public void TestBindDurableDeliverSubject() { Context.RunInJsServer(c => { CreateDefaultTestStream(c); IJetStream js = c.CreateJetStreamContext(); IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // create a durable push subscriber - has deliver subject ConsumerConfiguration ccDurPush = ConsumerConfiguration.Builder() .WithDurable(Durable(1)) .WithDeliverSubject(Deliver(1)) .Build(); jsm.AddOrUpdateConsumer(STREAM, ccDurPush); // create a durable pull subscriber - notice no deliver subject ConsumerConfiguration ccDurPull = ConsumerConfiguration.Builder() .WithDurable(Durable(2)) .Build(); jsm.AddOrUpdateConsumer(STREAM, ccDurPull); // try to pull subscribe against a push durable NATSJetStreamClientException e = Assert.Throws <NATSJetStreamClientException>( () => js.PullSubscribe(SUBJECT, PullSubscribeOptions.Builder().WithDurable(Durable(1)).Build())); Assert.Contains(JsSubConsumerAlreadyConfiguredAsPush.Id, e.Message); // try to pull bind against a push durable e = Assert.Throws <NATSJetStreamClientException>( () => js.PullSubscribe(SUBJECT, PullSubscribeOptions.BindTo(STREAM, Durable(1)))); Assert.Contains(JsSubConsumerAlreadyConfiguredAsPush.Id, e.Message); // this one is okay IJetStreamPullSubscription sub = js.PullSubscribe(SUBJECT, PullSubscribeOptions.Builder().WithDurable(Durable(2)).Build()); sub.Unsubscribe(); // so I can re-use the durable // try to push subscribe against a pull durable e = Assert.Throws <NATSJetStreamClientException>( () => js.PushSubscribeSync(SUBJECT, PushSubscribeOptions.Builder().WithDurable(Durable(2)).Build())); Assert.Contains(JsSubConsumerAlreadyConfiguredAsPull.Id, e.Message); // try to push bind against a pull durable e = Assert.Throws <NATSJetStreamClientException>( () => js.PushSubscribeSync(SUBJECT, PushSubscribeOptions.BindTo(STREAM, Durable(2)))); Assert.Contains(JsSubConsumerAlreadyConfiguredAsPull.Id, e.Message); // this one is okay js.PushSubscribeSync(SUBJECT, PushSubscribeOptions.Builder().WithDurable(Durable(1)).Build()); }); }
public void TestOrderedConsumerSync() { Console.SetOut(new ConsoleWriter(output)); Context.RunInJsServer(c => { // Setup IJetStream js = c.CreateJetStreamContext(); string subject = Subject(111); CreateMemoryStream(c, Stream(111), subject); // Get this in place before any subscriptions are made JetStream.PushMessageManagerFactoryImpl = (conn, so, cc, queueMode, syncMode) => new OrderedTestDropSimulator(conn, so, cc, queueMode, syncMode); // The options will be used in various ways PushSubscribeOptions pso = PushSubscribeOptions.Builder().WithOrdered(true).Build(); // Test queue exception NATSJetStreamClientException e = Assert.Throws <NATSJetStreamClientException>(() => js.PushSubscribeSync(subject, QUEUE, pso)); Assert.Contains(JsSubOrderedNotAllowOnQueues.Id, e.Message); // Setup sync subscription IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(subject, pso); Thread.Sleep(1000); // Published messages will be intercepted by the OrderedTestDropSimulator JsPublish(js, subject, 101, 6); ulong streamSeq = 1; while (streamSeq < 7) { Msg m = sub.NextMessage(1000); if (m != null) { Assert.Equal(streamSeq, m.MetaData.StreamSequence); Assert.Equal(ExpectedConSeqNums[streamSeq - 1], m.MetaData.ConsumerSequence); ++streamSeq; } } sub.Unsubscribe(); EnsureNotBound(sub); }); }
public void TestJetStreamPushDurableSubAsync() { Context.RunInJsServer(c => { // create the stream. CreateDefaultTestStream(c); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // publish some messages JsPublish(js, SUBJECT, 5); // Build our subscription options normally PushSubscribeOptions optionsSync1 = PushSubscribeOptions.Builder() .WithDurable(Durable(1)) .WithDeliverSubject(Deliver(1)) .Build(); _testPushDurableSubAsync(js, h => js.PushSubscribeAsync(SUBJECT, h, false, optionsSync1)); // bind long form jsm.AddOrUpdateConsumer(STREAM, ConsumerConfiguration.Builder() .WithDurable(Durable(2)) .WithDeliverSubject(Deliver(2)) .Build()); PushSubscribeOptions options2 = PushSubscribeOptions.Builder() .WithStream(STREAM) .WithDurable(Durable(2)) .WithBind(true) .Build(); _testPushDurableSubAsync(js, h => js.PushSubscribeAsync(null, h, false, options2)); // bind short form jsm.AddOrUpdateConsumer(STREAM, ConsumerConfiguration.Builder() .WithDurable(Durable(3)) .WithDeliverSubject(Deliver(3)) .Build()); PushSubscribeOptions options3 = PushSubscribeOptions.BindTo(STREAM, Durable(3)); _testPushDurableSubAsync(js, h => js.PushSubscribeAsync(null, h, false, options3)); }); }
private void VisitSubject(string subject, DeliverPolicy deliverPolicy, bool headersOnly, bool ordered, Action <Msg> action) { PushSubscribeOptions pso = PushSubscribeOptions.Builder() .WithOrdered(ordered) .WithConfiguration( ConsumerConfiguration.Builder() .WithAckPolicy(AckPolicy.None) .WithDeliverPolicy(deliverPolicy) .WithHeadersOnly(headersOnly) .Build()) .Build(); IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(subject, pso); try { bool lastTimedOut = false; ulong pending = sub.GetConsumerInformation().CalculatedPending; while (pending > 0) // no need to loop if nothing pending { try { Msg m = sub.NextMessage(js.Timeout); action.Invoke(m); if (--pending == 0) { return; } lastTimedOut = false; } catch (NATSTimeoutException) { if (lastTimedOut) { return; // two timeouts in a row is enough } lastTimedOut = true; } } } finally { sub.Unsubscribe(); } }
public void TestBindExceptions() { Context.RunInJsServer(c => { CreateDefaultTestStream(c); Assert.Throws <ArgumentException>( () => PushSubscribeOptions.Builder().WithStream(STREAM).WithBind(true).Build()); Assert.Throws <ArgumentException>( () => PushSubscribeOptions.Builder().WithDurable(DURABLE).WithBind(true).Build()); Assert.Throws <ArgumentException>( () => PushSubscribeOptions.Builder().WithStream(String.Empty).WithBind(true).Build()); Assert.Throws <ArgumentException>( () => PushSubscribeOptions.Builder().WithStream(STREAM).WithDurable(String.Empty).WithBind(true).Build()); }); }
public void TestPushFieldValidation() { PushSubscribeOptions.PushSubscribeOptionsBuilder builder = PushSubscribeOptions.Builder(); Assert.Throws <ArgumentException>(() => builder.WithStream(HasDot).Build()); Assert.Throws <ArgumentException>(() => builder.WithDurable(HasDot).Build()); ConsumerConfiguration ccBadDur = ConsumerConfiguration.Builder().WithDurable(HasDot).Build(); Assert.Throws <ArgumentException>(() => builder.WithConfiguration(ccBadDur).Build()); // durable directly PushSubscribeOptions.Builder().WithDurable(DURABLE).Build(); // in configuration ConsumerConfiguration cc = ConsumerConfiguration.Builder().WithDurable(DURABLE).Build(); PushSubscribeOptions.Builder().WithConfiguration(cc).Build(); // new helper ConsumerConfiguration.Builder().WithDurable(DURABLE).BuildPushSubscribeOptions(); }
public void TestPushAffirmative() { PushSubscribeOptions so = PushSubscribeOptions.Builder().Build(); // starts out all null which is fine Assert.Null(so.Stream); Assert.Null(so.Durable); Assert.Null(so.DeliverSubject); so = PushSubscribeOptions.Builder() .WithStream(STREAM).WithDurable(DURABLE).WithDeliverSubject(DELIVER).Build(); Assert.Equal(STREAM, so.Stream); Assert.Equal(DURABLE, so.Durable); Assert.Equal(DELIVER, so.DeliverSubject); // demonstrate that you can clear the builder so = PushSubscribeOptions.Builder() .WithStream(null).WithDeliverSubject(null).WithDurable(null).Build(); Assert.Null(so.Stream); Assert.Null(so.Durable); Assert.Null(so.DeliverSubject); Assert.False(so.Pull); }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("NATS JetStream Push Subscribe Bind Durable", args, Usage) .DefaultStream("fs-stream") .DefaultSubject("fs-subject") .Build(); string subjectWild = helper.Subject + ".*"; string subjectA = helper.Subject + ".A"; string subjectB = helper.Subject + ".B"; try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Create a JetStreamManagement context. IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // Use the utility to create a stream stored in memory. JsUtils.CreateStreamExitWhenExists(jsm, helper.Stream, subjectWild); // Create our JetStream context to publish and receive JetStream messages. IJetStream js = c.CreateJetStreamContext(); JsUtils.Publish(js, subjectA, 1); JsUtils.Publish(js, subjectB, 1); JsUtils.Publish(js, subjectA, 1); JsUtils.Publish(js, subjectB, 1); // 1. create a subscription that subscribes to the wildcard subject ConsumerConfiguration cc = ConsumerConfiguration.Builder() .WithAckPolicy(AckPolicy.None) // don't want to worry about acking messages. .Build(); PushSubscribeOptions pso = PushSubscribeOptions.Builder() .WithConfiguration(cc) .Build(); IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(subjectWild, pso); c.Flush(5000); Msg m = sub.NextMessage(1000); Console.WriteLine("\n1A1. Message should be from '" + subjectA + "', Sequence #1. " + "It was: '" + m.Subject + "', Seq #" + m.MetaData.StreamSequence); m = sub.NextMessage(1000); Console.WriteLine("1B2. Message should be from '" + subjectB + "', Sequence #2. " + "It was: '" + m.Subject + "', Seq #" + m.MetaData.StreamSequence); m = sub.NextMessage(1000); Console.WriteLine("1A3. Message should be from '" + subjectA + "', Sequence #3. " + "It was: '" + m.Subject + "', Seq #" + m.MetaData.StreamSequence); m = sub.NextMessage(1000); Console.WriteLine("1B4. Message should be from '" + subjectB + "', Sequence #4. " + "It was: '" + m.Subject + "', Seq #" + m.MetaData.StreamSequence); // 2. create a subscription that subscribes only to the A subject cc = ConsumerConfiguration.Builder() .WithAckPolicy(AckPolicy.None) // don't want to worry about acking messages. .WithFilterSubject(subjectA) .Build(); pso = PushSubscribeOptions.Builder() .WithConfiguration(cc) .Build(); sub = js.PushSubscribeSync(subjectWild, pso); c.Flush(5000); m = sub.NextMessage(1000); Console.WriteLine("\n2A1. Message should be from '" + subjectA + "', Sequence #1. " + "It was: '" + m.Subject + "', Seq #" + m.MetaData.StreamSequence); m = sub.NextMessage(1000); Console.WriteLine("2A3. Message should be from '" + subjectA + "', Sequence #3. " + "It was: '" + m.Subject + "', Seq #" + m.MetaData.StreamSequence); try { sub.NextMessage(1000); Console.WriteLine("2x. NOPE! Should not have gotten here"); } catch (NATSTimeoutException) // timeout means there are no messages available { Console.WriteLine("2x. There was no message available."); } // 3. create a subscription that subscribes only to the A subject cc = ConsumerConfiguration.Builder() .WithAckPolicy(AckPolicy.None) // don't want to worry about acking messages. .WithFilterSubject(subjectB) .Build(); pso = PushSubscribeOptions.Builder() .WithConfiguration(cc) .Build(); sub = js.PushSubscribeSync(subjectWild, pso); c.Flush(5000); m = sub.NextMessage(1000); Console.WriteLine("\n3A2. Message should be from '" + subjectB + "', Sequence #2. " + "It was: '" + m.Subject + "', Seq #" + m.MetaData.StreamSequence); m = sub.NextMessage(1000); Console.WriteLine("3A4. Message should be from '" + subjectB + "', Sequence #4. " + "It was: '" + m.Subject + "', Seq #" + m.MetaData.StreamSequence); try { sub.NextMessage(1000); Console.WriteLine("3x. NOPE! Should not have gotten here"); } catch (NATSTimeoutException) // timeout means there are no messages available { Console.WriteLine("3x. There was no message available."); } Console.WriteLine(); // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
public void TestFilterSubjectEphemeral() { Context.RunInJsServer(c => { // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); string subjectWild = SUBJECT + ".*"; string subjectA = SUBJECT + ".A"; string subjectB = SUBJECT + ".B"; // create the stream. CreateMemoryStream(c, STREAM, subjectWild); JsPublish(js, subjectA, 1); JsPublish(js, subjectB, 1); JsPublish(js, subjectA, 1); JsPublish(js, subjectB, 1); // subscribe to the wildcard ConsumerConfiguration cc = ConsumerConfiguration.Builder().WithAckPolicy(AckPolicy.None).Build(); PushSubscribeOptions pso = PushSubscribeOptions.Builder().WithConfiguration(cc).Build(); IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(subjectWild, pso); c.Flush(1000); Msg m = sub.NextMessage(1000); Assert.Equal(subjectA, m.Subject); Assert.Equal(1U, m.MetaData.StreamSequence); m = sub.NextMessage(1000); Assert.Equal(subjectB, m.Subject); Assert.Equal(2U, m.MetaData.StreamSequence); m = sub.NextMessage(1000); Assert.Equal(subjectA, m.Subject); Assert.Equal(3U, m.MetaData.StreamSequence); m = sub.NextMessage(1000); Assert.Equal(subjectB, m.Subject); Assert.Equal(4U, m.MetaData.StreamSequence); // subscribe to A cc = ConsumerConfiguration.Builder().WithFilterSubject(subjectA).WithAckPolicy(AckPolicy.None).Build(); pso = PushSubscribeOptions.Builder().WithConfiguration(cc).Build(); sub = js.PushSubscribeSync(subjectWild, pso); c.Flush(1000); m = sub.NextMessage(1000); Assert.Equal(subjectA, m.Subject); Assert.Equal(1U, m.MetaData.StreamSequence); m = sub.NextMessage(1000); Assert.Equal(subjectA, m.Subject); Assert.Equal(3U, m.MetaData.StreamSequence); Assert.Throws <NATSTimeoutException>(() => sub.NextMessage(1000)); // subscribe to B cc = ConsumerConfiguration.Builder().WithFilterSubject(subjectB).WithAckPolicy(AckPolicy.None).Build(); pso = PushSubscribeOptions.Builder().WithConfiguration(cc).Build(); sub = js.PushSubscribeSync(subjectWild, pso); c.Flush(1000); m = sub.NextMessage(1000); Assert.Equal(subjectB, m.Subject); Assert.Equal(2U, m.MetaData.StreamSequence); m = sub.NextMessage(1000); Assert.Equal(subjectB, m.Subject); Assert.Equal(4U, m.MetaData.StreamSequence); Assert.Throws <NATSTimeoutException>(() => sub.NextMessage(1000)); }); }
public void TestJetStreamSubscribe() { Context.RunInJsServer(c => { IJetStream js = c.CreateJetStreamContext(); IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); CreateDefaultTestStream(jsm); JsPublish(js); // default ephemeral subscription. IJetStreamPushSyncSubscription s = js.PushSubscribeSync(SUBJECT); Msg m = s.NextMessage(DefaultTimeout); Assert.NotNull(m); Assert.Equal(DATA, Encoding.UTF8.GetString(m.Data)); IList <String> names = jsm.GetConsumerNames(STREAM); Assert.Equal(1, names.Count); // default subscribe options // ephemeral subscription. s = js.PushSubscribeSync(SUBJECT, PushSubscribeOptions.Builder().Build()); m = s.NextMessage(DefaultTimeout); Assert.NotNull(m); Assert.Equal(DATA, Encoding.UTF8.GetString(m.Data)); names = jsm.GetConsumerNames(STREAM); Assert.Equal(2, names.Count); // set the stream PushSubscribeOptions pso = PushSubscribeOptions.Builder() .WithStream(STREAM).WithDurable(DURABLE).Build(); s = js.PushSubscribeSync(SUBJECT, pso); m = s.NextMessage(DefaultTimeout); Assert.NotNull(m); Assert.Equal(DATA, Encoding.UTF8.GetString(m.Data)); names = jsm.GetConsumerNames(STREAM); Assert.Equal(3, names.Count); // coverage js.PushSubscribeSync(SUBJECT); js.PushSubscribeSync(SUBJECT, (PushSubscribeOptions)null); js.PushSubscribeSync(SUBJECT, QUEUE, null); js.PushSubscribeAsync(SUBJECT, (o, a) => {}, false); js.PushSubscribeAsync(SUBJECT, (o, a) => {}, false, null); js.PushSubscribeAsync(SUBJECT, QUEUE, (o, a) => {}, false, null); // bind with w/o subject jsm.AddOrUpdateConsumer(STREAM, ConsumerConfiguration.Builder() .WithDurable(Durable(101)) .WithDeliverSubject(Deliver(101)) .Build()); PushSubscribeOptions psoBind = PushSubscribeOptions.BindTo(STREAM, Durable(101)); js.PushSubscribeSync(null, psoBind).Unsubscribe(); js.PushSubscribeSync("", psoBind).Unsubscribe(); js.PushSubscribeAsync(null, (o, a) => { }, false, psoBind).Unsubscribe(); js.PushSubscribeAsync("", (o, a) => { }, false, psoBind); jsm.AddOrUpdateConsumer(STREAM, ConsumerConfiguration.Builder() .WithDurable(Durable(102)) .WithDeliverSubject(Deliver(102)) .WithDeliverGroup(Queue(102)) .Build()); psoBind = PushSubscribeOptions.BindTo(STREAM, Durable(102)); js.PushSubscribeSync(null, Queue(102), psoBind).Unsubscribe(); js.PushSubscribeSync("", Queue(102), psoBind).Unsubscribe(); js.PushSubscribeAsync(null, Queue(102), (o, a) => { }, false, psoBind).Unsubscribe(); js.PushSubscribeAsync("", Queue(102), (o, a) => { }, false, psoBind); }); }
public void TestDeliveryPolicy() { Context.RunInJsServer(c => { IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); IJetStream js = c.CreateJetStreamContext(); CreateMemoryStream(jsm, STREAM, SUBJECT_STAR); string subjectA = SubjectDot("A"); string subjectB = SubjectDot("B"); js.Publish(subjectA, DataBytes(1)); js.Publish(subjectA, DataBytes(2)); Thread.Sleep(1500); js.Publish(subjectA, DataBytes(3)); js.Publish(subjectB, DataBytes(91)); js.Publish(subjectB, DataBytes(92)); // DeliverPolicy.All PushSubscribeOptions pso = PushSubscribeOptions.Builder() .WithConfiguration(ConsumerConfiguration.Builder().WithDeliverPolicy(DeliverPolicy.All).Build()) .Build(); IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(subjectA, pso); Msg m1 = sub.NextMessage(1000); AssertMessage(m1, 1); Msg m2 = sub.NextMessage(1000); AssertMessage(m2, 2); Msg m3 = sub.NextMessage(1000); AssertMessage(m3, 3); // DeliverPolicy.Last pso = PushSubscribeOptions.Builder() .WithConfiguration(ConsumerConfiguration.Builder().WithDeliverPolicy(DeliverPolicy.Last).Build()) .Build(); sub = js.PushSubscribeSync(subjectA, pso); Msg m = sub.NextMessage(1000); AssertMessage(m, 3); AssertNoMoreMessages(sub); // DeliverPolicy.New - No new messages between subscribe and next message pso = PushSubscribeOptions.Builder() .WithConfiguration(ConsumerConfiguration.Builder().WithDeliverPolicy(DeliverPolicy.New).Build()) .Build(); sub = js.PushSubscribeSync(subjectA, pso); AssertNoMoreMessages(sub); // DeliverPolicy.New - New message between subscribe and next message sub = js.PushSubscribeSync(subjectA, pso); js.Publish(subjectA, DataBytes(4)); m = sub.NextMessage(1000); AssertMessage(m, 4); // DeliverPolicy.ByStartSequence pso = PushSubscribeOptions.Builder() .WithConfiguration(ConsumerConfiguration.Builder() .WithDeliverPolicy(DeliverPolicy.ByStartSequence) .WithStartSequence(3) .Build()) .Build(); sub = js.PushSubscribeSync(subjectA, pso); m = sub.NextMessage(1000); AssertMessage(m, 3); m = sub.NextMessage(1000); AssertMessage(m, 4); // DeliverPolicy.ByStartTime pso = PushSubscribeOptions.Builder() .WithConfiguration(ConsumerConfiguration.Builder() .WithDeliverPolicy(DeliverPolicy.ByStartTime) .WithStartTime(m3.MetaData.Timestamp.AddSeconds(-1)) .Build()) .Build(); sub = js.PushSubscribeSync(subjectA, pso); m = sub.NextMessage(1000); AssertMessage(m, 3); m = sub.NextMessage(1000); AssertMessage(m, 4); // DeliverPolicy.LastPerSubject pso = PushSubscribeOptions.Builder() .WithConfiguration(ConsumerConfiguration.Builder() .WithDeliverPolicy(DeliverPolicy.LastPerSubject) .WithFilterSubject(subjectA) .Build()) .Build(); sub = js.PushSubscribeSync(subjectA, pso); m = sub.NextMessage(1000); AssertMessage(m, 4); // DeliverPolicy.ByStartSequence with a deleted record PublishAck pa4 = js.Publish(subjectA, DataBytes(4)); PublishAck pa5 = js.Publish(subjectA, DataBytes(5)); js.Publish(subjectA, DataBytes(6)); jsm.DeleteMessage(STREAM, pa4.Seq); jsm.DeleteMessage(STREAM, pa5.Seq); pso = ConsumerConfiguration.Builder() .WithDeliverPolicy(DeliverPolicy.ByStartSequence) .WithStartSequence(pa4.Seq) .BuildPushSubscribeOptions(); sub = js.PushSubscribeSync(subjectA, pso); m = sub.NextMessage(1000); AssertMessage(m, 6); }); }
public KeyValueWatchSubscription(KeyValue kv, string keyPattern, IKeyValueWatcher watcher, params KeyValueWatchOption[] watchOptions) { string subject = kv.RawKeySubject(keyPattern); // figure out the result options bool headersOnly = false; bool includeDeletes = true; DeliverPolicy deliverPolicy = DeliverPolicy.LastPerSubject; foreach (KeyValueWatchOption wo in watchOptions) { switch (wo) { case KeyValueWatchOption.MetaOnly: headersOnly = true; break; case KeyValueWatchOption.IgnoreDelete: includeDeletes = false; break; case KeyValueWatchOption.UpdatesOnly: deliverPolicy = DeliverPolicy.New; break; case KeyValueWatchOption.IncludeHistory: deliverPolicy = DeliverPolicy.All; break; } } if (deliverPolicy == DeliverPolicy.New) { endOfDataSent = new InterlockedBoolean(true); watcher.EndOfData(); } else { KeyValueEntry kveCheckPending = kv._kvGetLastMessage(keyPattern); if (kveCheckPending == null) { endOfDataSent = new InterlockedBoolean(true); watcher.EndOfData(); } else { endOfDataSent = new InterlockedBoolean(false); } } PushSubscribeOptions pso = PushSubscribeOptions.Builder() .WithStream(kv.StreamName) .WithOrdered(true) .WithConfiguration( ConsumerConfiguration.Builder() .WithAckPolicy(AckPolicy.None) .WithDeliverPolicy(deliverPolicy) .WithHeadersOnly(headersOnly) .WithFilterSubject(subject) .Build()) .Build(); EventHandler <MsgHandlerEventArgs> handler = (sender, args) => { KeyValueEntry kve = new KeyValueEntry(args.msg); if (includeDeletes || kve.Operation.Equals(KeyValueOperation.Put)) { watcher.Watch(kve); } if (endOfDataSent.IsFalse() && kve.Delta == 0) { endOfDataSent.Set(true); watcher.EndOfData(); } }; sub = kv.js.PushSubscribeAsync(subject, handler, false, pso); if (endOfDataSent.IsFalse()) { ulong pending = sub.GetConsumerInformation().CalculatedPending; if (pending == 0) { endOfDataSent.Set(true); watcher.EndOfData(); } } }
public void TestAcks() { Context.RunInJsServer(c => { // create the stream. CreateDefaultTestStream(c); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); ConsumerConfiguration cc = ConsumerConfiguration.Builder().WithAckWait(1500).Build(); // Build our subscription options. PushSubscribeOptions options = PushSubscribeOptions.Builder() .WithConfiguration(cc) .Build(); IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(SUBJECT, options); c.Flush(DefaultTimeout); // flush outgoing communication with/to the server // TERM JsPublish(js, SUBJECT, "TERM", 1); Msg m = sub.NextMessage(DefaultTimeout); Assert.NotNull(m); Assert.Equal("TERM1", Encoding.ASCII.GetString(m.Data)); m.Term(); AssertNoMoreMessages(sub); // Ack Wait timeout JsPublish(js, SUBJECT, "WAIT", 1); m = sub.NextMessage(DefaultTimeout); Assert.NotNull(m); Assert.Equal("WAIT1", Encoding.ASCII.GetString(m.Data)); Thread.Sleep(2000); m.Ack(); m = sub.NextMessage(DefaultTimeout); Assert.NotNull(m); Assert.Equal("WAIT1", Encoding.ASCII.GetString(m.Data)); // In Progress JsPublish(js, SUBJECT, "PRO", 1); m = sub.NextMessage(DefaultTimeout); Assert.NotNull(m); Assert.Equal("PRO1", Encoding.ASCII.GetString(m.Data)); m.InProgress(); Thread.Sleep(750); m.InProgress(); Thread.Sleep(750); m.InProgress(); Thread.Sleep(750); m.InProgress(); Thread.Sleep(750); m.Ack(); AssertNoMoreMessages(sub); // ACK Sync JsPublish(js, SUBJECT, "ACKSYNC", 1); m = sub.NextMessage(DefaultTimeout); Assert.NotNull(m); Assert.Equal("ACKSYNC1", Encoding.ASCII.GetString(m.Data)); m.AckSync(DefaultTimeout); AssertNoMoreMessages(sub); // NAK JsPublish(js, SUBJECT, "NAK", 1); m = sub.NextMessage(DefaultTimeout); Assert.NotNull(m); Assert.Equal("NAK1", Encoding.ASCII.GetString(m.Data)); m.Nak(); m = sub.NextMessage(DefaultTimeout); Assert.NotNull(m); Assert.Equal("NAK1", Encoding.ASCII.GetString(m.Data)); m.Ack(); AssertNoMoreMessages(sub); JsPublish(js, SUBJECT, "NAK", 2, 1); m = sub.NextMessage(1000); Assert.NotNull(m); Assert.Equal("NAK2", Encoding.ASCII.GetString(m.Data)); m.NakWithDelay(3000); Assert.Throws <NATSTimeoutException>(() => sub.NextMessage(500)); m = sub.NextMessage(3000); Assert.NotNull(m); Assert.Equal("NAK2", Encoding.ASCII.GetString(m.Data)); m.Ack(); Assert.Throws <NATSTimeoutException>(() => sub.NextMessage(500)); JsPublish(js, SUBJECT, "NAK", 3, 1); m = sub.NextMessage(1000); Assert.NotNull(m); Assert.Equal("NAK3", Encoding.ASCII.GetString(m.Data)); m.NakWithDelay(Duration.OfSeconds(3)); // coverage to use both nakWithDelay Assert.Throws <NATSTimeoutException>(() => sub.NextMessage(500)); m = sub.NextMessage(3000); Assert.NotNull(m); Assert.Equal("NAK3", Encoding.ASCII.GetString(m.Data)); m.Ack(); Assert.Throws <NATSTimeoutException>(() => sub.NextMessage(500)); }); }
public void TestPushAsyncFlowControl() { InterlockedInt fcps = new InterlockedInt(); Action <Options> optionsModifier = opts => { opts.FlowControlProcessedEventHandler = (sender, args) => { fcps.Increment(); }; }; Context.RunInJsServer(new TestServerInfo(TestSeedPorts.AutoPort.Increment()), optionsModifier, c => { // create the stream. CreateDefaultTestStream(c); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); byte[] data = new byte[8192]; int msgCount = 1000; for (int x = 100_000; x < msgCount + 100_000; x++) { byte[] fill = Encoding.ASCII.GetBytes("" + x); Array.Copy(fill, 0, data, 0, 6); js.Publish(new Msg(SUBJECT, data)); } InterlockedInt count = new InterlockedInt(); HashSet <string> set = new HashSet <string>(); CountdownEvent latch = new CountdownEvent(msgCount); // create our message handler, does not ack void Handler(object sender, MsgHandlerEventArgs args) { byte[] fill = new byte[6]; Array.Copy(args.Message.Data, 0, fill, 0, 6); string id = Encoding.ASCII.GetString(fill); if (set.Add(id)) { count.Increment(); } args.Message.Ack(); latch.Signal(); } // subscribe using the handler ConsumerConfiguration cc = ConsumerConfiguration.Builder().WithFlowControl(1000).Build(); PushSubscribeOptions pso = PushSubscribeOptions.Builder().WithConfiguration(cc).Build(); js.PushSubscribeAsync(SUBJECT, Handler, false, pso); // wait for messages to arrive using the countdown latch. latch.Wait(); Assert.Equal(msgCount, count.Read()); Assert.True(fcps.Read() > 0); }); }
public void TestHandlerAutoAck() { Context.RunInJsServer(c => { // create the stream. CreateDefaultTestStream(c); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // publish some messages JsPublish(js, SUBJECT, 10); // 1. auto ack true CountdownEvent latch1 = new CountdownEvent(10); int handlerReceived1 = 0; // create our message handler, does not ack void Handler1(object sender, MsgHandlerEventArgs args) { handlerReceived1++; latch1.Signal(); } // subscribe using the handler, auto ack true PushSubscribeOptions pso1 = PushSubscribeOptions.Builder() .WithDurable(Durable(1)).Build(); IJetStreamPushAsyncSubscription asub = js.PushSubscribeAsync(SUBJECT, Handler1, true, pso1); // wait for messages to arrive using the countdown latch. latch1.Wait(); Assert.Equal(10, handlerReceived1); asub.Unsubscribe(); // check that all the messages were read by the durable IJetStreamPushSyncSubscription ssub = js.PushSubscribeSync(SUBJECT, pso1); AssertNoMoreMessages(ssub); // 2. auto ack false CountdownEvent latch2 = new CountdownEvent(10); int handlerReceived2 = 0; // create our message handler, also does not ack void Handler2(object sender, MsgHandlerEventArgs args) { handlerReceived2++; latch2.Signal(); } // subscribe using the handler, auto ack false ConsumerConfiguration cc = ConsumerConfiguration.Builder().WithAckWait(500).Build(); PushSubscribeOptions pso2 = PushSubscribeOptions.Builder() .WithDurable(Durable(2)).WithConfiguration(cc).Build(); asub = js.PushSubscribeAsync(SUBJECT, Handler2, false, pso2); // wait for messages to arrive using the countdown latch. latch2.Wait(); Assert.Equal(10, handlerReceived2); Thread.Sleep(2000); // just give it time for the server to realize the messages are not ack'ed asub.Unsubscribe(); // check that we get all the messages again ssub = js.PushSubscribeSync(SUBJECT, pso2); Assert.Equal(10, ReadMessagesAck(ssub).Count); }); }
private void ChangeOkPush(IJetStream js, ConsumerConfiguration.ConsumerConfigurationBuilder builder) { js.PushSubscribeSync(SUBJECT, PushSubscribeOptions.Builder().WithConfiguration(builder.Build()).Build()).Unsubscribe(); }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("Push Subscribe Basic Sync", args, Usage) .DefaultStream("example-stream") .DefaultSubject("example-subject") .DefaultCount(0, true) // true indicated 0 means unlimited // .DefaultDurable("push-sub-basic-sync-durable") .Build(); int count = helper.Count < 1 ? int.MaxValue : helper.Count; try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // The stream (and data) must exist JsUtils.ExitIfStreamNotExists(c, helper.Stream); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Build our subscription options. // * A push subscription means the server will "push" us messages. // * Durable means the server will remember where we are if we use that name. // * Durable can by null or empty, the builder treats them the same. // * The stream name is not technically required. If it is not provided, the // code building the subscription will look it up by making a request to the server. // If you know the stream name, you might as well supply it and save a trip to the server. PushSubscribeOptions so = PushSubscribeOptions.Builder() .WithStream(helper.Stream) .WithDurable(helper.Durable) // it's okay if this is null, the builder handles it .Build(); // Subscribe synchronously, then just wait for messages. IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(helper.Subject, so); c.Flush(5000); int red = 0; while (count > 0) { try { Msg msg = sub.NextMessage(1000); Console.WriteLine("\nMessage Received:"); if (msg.HasHeaders) { Console.WriteLine(" Headers:"); foreach (string key in msg.Header.Keys) { foreach (string value in msg.Header.GetValues(key)) { Console.WriteLine($" {key}: {value}"); } } } Console.WriteLine(" Subject: {0}\n Data: {1}\n", msg.Subject, Encoding.UTF8.GetString(msg.Data)); Console.WriteLine(" " + msg.MetaData); // Because this is a synchronous subscriber, there's no auto-ack. // The default Consumer Configuration AckPolicy is Explicit // so we need to ack the message or it'll be redelivered. msg.Ack(); ++red; --count; } catch (NATSTimeoutException) // timeout means there are no messages available { count = 0; // ran out of messages } } Console.WriteLine("\n" + red + " message(s) were received.\n"); sub.Unsubscribe(); c.Flush(5000); } } catch (Exception ex) { helper.ReportException(ex); } }
public void TestMoreCreateSubscriptionErrors() { Context.RunInJsServer(c => { // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); NATSJetStreamClientException e = Assert.Throws <NATSJetStreamClientException>(() => js.PushSubscribeSync(SUBJECT)); Assert.Contains(JsSubNoMatchingStreamForSubject.Id, e.Message); // create the stream. CreateDefaultTestStream(c); // general pull push validation ConsumerConfiguration ccPush = ConsumerConfiguration.Builder().WithDurable("pulldur").WithDeliverGroup("cantHave").Build(); PullSubscribeOptions pullCantHaveDlvrGrp = PullSubscribeOptions.Builder().WithConfiguration(ccPush).Build(); e = Assert.Throws <NATSJetStreamClientException>(() => js.PullSubscribe(SUBJECT, pullCantHaveDlvrGrp)); Assert.Contains(JsSubPullCantHaveDeliverGroup.Id, e.Message); ccPush = ConsumerConfiguration.Builder().WithDurable("pulldur").WithDeliverSubject("cantHave").Build(); PullSubscribeOptions pullCantHaveDlvrSub = PullSubscribeOptions.Builder().WithConfiguration(ccPush).Build(); e = Assert.Throws <NATSJetStreamClientException>(() => js.PullSubscribe(SUBJECT, pullCantHaveDlvrSub)); Assert.Contains(JsSubPullCantHaveDeliverSubject.Id, e.Message); ccPush = ConsumerConfiguration.Builder().WithMaxPullWaiting(1).Build(); PushSubscribeOptions pushSo = PushSubscribeOptions.Builder().WithConfiguration(ccPush).Build(); e = Assert.Throws <NATSJetStreamClientException>(() => js.PushSubscribeSync(SUBJECT, pushSo)); Assert.Contains(JsSubPushCantHaveMaxPullWaiting.Id, e.Message); ccPush = ConsumerConfiguration.Builder().WithMaxPullWaiting(-1).Build(); pushSo = PushSubscribeOptions.Builder().WithConfiguration(ccPush).Build(); js.PushSubscribeSync(SUBJECT, pushSo); ccPush = ConsumerConfiguration.Builder().WithMaxBatch(1).Build(); pushSo = PushSubscribeOptions.Builder().WithConfiguration(ccPush).Build(); e = Assert.Throws <NATSJetStreamClientException>(() => js.PushSubscribeSync(SUBJECT, pushSo)); ccPush = ConsumerConfiguration.Builder().WithMaxBatch(-1).Build(); pushSo = PushSubscribeOptions.Builder().WithConfiguration(ccPush).Build(); js.PushSubscribeSync(SUBJECT, pushSo); Assert.Contains(JsSubPushCantHaveMaxBatch.Id, e.Message); ccPush = ConsumerConfiguration.Builder().WithMaxBytes(1).Build(); pushSo = PushSubscribeOptions.Builder().WithConfiguration(ccPush).Build(); e = Assert.Throws <NATSJetStreamClientException>(() => js.PushSubscribeSync(SUBJECT, pushSo)); ccPush = ConsumerConfiguration.Builder().WithMaxBytes(-1).Build(); pushSo = PushSubscribeOptions.Builder().WithConfiguration(ccPush).Build(); js.PushSubscribeSync(SUBJECT, pushSo); Assert.Contains(JsSubPushCantHaveMaxBytes.Id, e.Message); // create some consumers PushSubscribeOptions psoDurNoQ = PushSubscribeOptions.Builder().WithDurable("durNoQ").Build(); js.PushSubscribeSync(SUBJECT, psoDurNoQ); PushSubscribeOptions psoDurYesQ = PushSubscribeOptions.Builder().WithDurable("durYesQ").Build(); js.PushSubscribeSync(SUBJECT, "yesQ", psoDurYesQ); // already bound e = Assert.Throws <NATSJetStreamClientException>(() => js.PushSubscribeSync(SUBJECT, psoDurNoQ)); Assert.Contains(JsSubConsumerAlreadyBound.Id, e.Message); // queue match PushSubscribeOptions qmatch = PushSubscribeOptions.Builder() .WithDurable("qmatchdur").WithDeliverGroup("qmatchq").Build(); e = Assert.Throws <NATSJetStreamClientException>(() => js.PushSubscribeSync(SUBJECT, "qnotmatch", qmatch)); Assert.Contains(JsSubQueueDeliverGroupMismatch.Id, e.Message); // queue vs config e = Assert.Throws <NATSJetStreamClientException>(() => js.PushSubscribeSync(SUBJECT, "notConfigured", psoDurNoQ)); Assert.Contains(JsSubExistingConsumerNotQueue.Id, e.Message); PushSubscribeOptions psoNoVsYes = PushSubscribeOptions.Builder().WithDurable("durYesQ").Build(); e = Assert.Throws <NATSJetStreamClientException>(() => js.PushSubscribeSync(SUBJECT, psoNoVsYes)); Assert.Contains(JsSubExistingConsumerIsQueue.Id, e.Message); PushSubscribeOptions psoYesVsNo = PushSubscribeOptions.Builder().WithDurable("durYesQ").Build(); e = Assert.Throws <NATSJetStreamClientException>(() => js.PushSubscribeSync(SUBJECT, "qnotmatch", psoYesVsNo)); Assert.Contains(JsSubExistingQueueDoesNotMatchRequestedQueue.Id, e.Message); // flow control heartbeat push / pull ConsumerConfiguration ccFc = ConsumerConfiguration.Builder().WithDurable("ccFcDur").WithFlowControl(1000).Build(); ConsumerConfiguration ccHb = ConsumerConfiguration.Builder().WithDurable("ccHbDur").WithIdleHeartbeat(1000).Build(); PullSubscribeOptions psoPullCcFc = PullSubscribeOptions.Builder().WithConfiguration(ccFc).Build(); e = Assert.Throws <NATSJetStreamClientException>(() => js.PullSubscribe(SUBJECT, psoPullCcFc)); Assert.Contains(JsSubFcHbNotValidPull.Id, e.Message); PullSubscribeOptions psoPullCcHb = PullSubscribeOptions.Builder().WithConfiguration(ccHb).Build(); e = Assert.Throws <NATSJetStreamClientException>(() => js.PullSubscribe(SUBJECT, psoPullCcHb)); Assert.Contains(JsSubFcHbNotValidPull.Id, e.Message); PushSubscribeOptions psoPushCcFc = PushSubscribeOptions.Builder().WithConfiguration(ccFc).Build(); e = Assert.Throws <NATSJetStreamClientException>(() => js.PushSubscribeSync(SUBJECT, "cantHaveQ", psoPushCcFc)); Assert.Contains(JsSubFcHbHbNotValidQueue.Id, e.Message); PushSubscribeOptions psoPushCcHb = PushSubscribeOptions.Builder().WithConfiguration(ccHb).Build(); e = Assert.Throws <NATSJetStreamClientException>(() => js.PushSubscribeSync(SUBJECT, "cantHaveQ", psoPushCcHb)); Assert.Contains(JsSubFcHbHbNotValidQueue.Id, e.Message); }); }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("NATS JetStream Push Subscribe Bind Durable", args, Usage) .DefaultStream("fs-stream") .DefaultSubject("fs-subject") .Build(); string subjectNoAck = helper.Subject + "noack"; string subjectAck = helper.Subject + "ack"; string deliverNoAck = helper.DeliverSubject + "noack"; string deliverAck = helper.DeliverSubject + "ack"; try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Create a JetStreamManagement context. IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // Use the utility to create a stream stored in memory. JsUtils.CreateStreamExitWhenExists(jsm, helper.Stream, subjectNoAck, subjectAck); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // The server uses the delivery subject as both an inbox for a JetStream subscription // and as a core nats messages subject. // BUT BE CAREFUL. THIS IS STILL A JETSTREAM SUBJECT AND ALL MESSAGES // ADHERE TO THE ACK POLICY // NoAck 1. Set up the noAck consumer / deliver subject configuration ConsumerConfiguration cc = ConsumerConfiguration.Builder() .WithAckPolicy(AckPolicy.None) .WithAckWait(1000) .Build(); PushSubscribeOptions pso = PushSubscribeOptions.Builder() .WithDeliverSubject(deliverNoAck) .WithConfiguration(cc) .Build(); // NoAck 2. Set up the JetStream and core subscriptions // Notice the JetStream subscribes to the real subject // and the core subscribes to the delivery subject // Order matters, you must do the JetStream subscribe first // But you also must make sure the core sub is made // before messages are published IJetStreamPushSyncSubscription jsSub = js.PushSubscribeSync(subjectNoAck, pso); c.Flush(5000); ISyncSubscription coreSub = c.SubscribeSync(deliverNoAck); // NoAck 3. JsUtils.Publish to the real subject JsUtils.Publish(js, subjectNoAck, "A", 1); // NoAck 4. Read the message with the js no ack subscription. No need to ack Msg msg = jsSub.NextMessage(1000); PrintMessage("\nNoAck 4. Read w/JetStream sub", msg); // NoAck 5. Read the message with the core subscription on the // no ack deliver subject. Since this message is a JetStream // message we could ack. But we don't have to since the consumer // was setup as AckPolicy None msg = coreSub.NextMessage(1000); PrintMessage("NoAck 5. Read w/core sub", msg); // NoAck 6. Thread.Sleep longer than the ack wait period to check and make sure the // message is not replayed Thread.Sleep(1100); try { coreSub.NextMessage(1000); Console.WriteLine("NoAck 6. NOPE! Should not have gotten here"); } catch (NATSTimeoutException) // timeout means there are no messages available { Console.WriteLine("NoAck 6. Read w/core sub.\nAck Policy is none so no replay even though message was not Ack'd.\nThere was no message available."); } // Ack 1. Set up the Ack consumer / deliver subject configuration cc = ConsumerConfiguration.Builder() .WithAckPolicy(AckPolicy.Explicit) .WithAckWait(1000) .Build(); pso = PushSubscribeOptions.Builder() .WithDeliverSubject(deliverAck) .WithConfiguration(cc) .Build(); // Ack 2. Set up the JetStream and core subscriptions jsSub = js.PushSubscribeSync(subjectAck, pso); c.Flush(5000); coreSub = c.SubscribeSync(deliverAck); // Ack 3. JsUtils.Publish to the real subject JsUtils.Publish(js, subjectAck, "B", 1); // Ack 4. Read the message with the js no ack subscription. No need to ack msg = jsSub.NextMessage(1000); PrintMessage("\nAck 4. Read w/JetStream sub", msg); // Ack 5. Read the message with the core subscription on the // ack deliver subject. // Even though it is read on a core subscription // it still is a JetStream message. Don't ack this time msg = coreSub.NextMessage(1000); PrintMessage("Ack 5. Read w/core sub", msg); // Ack 6. Thread.Sleep longer than the ack wait period to check and // see that the message is re-delivered. Ack this time. Thread.Sleep(1100); msg = coreSub.NextMessage(1000); msg.Ack(); PrintMessage("Ack 6. Read w/core sub.\nWasn't Ack'd after step 'Ack 5.' so message was replayed.", msg); // Ack 7. Thread.Sleep longer than the ack wait period. The message // is not re-delivered this time Thread.Sleep(1100); try { coreSub.NextMessage(1000); Console.WriteLine("Ack 7. NOPE! Should not have gotten here"); } catch (NATSTimeoutException) // timeout means there are no messages available { Console.WriteLine("Ack 7. Read w/core sub.\nMessage received by core sub in step 'Ack 6.' was JetStream so it was Ack'd and therefore not replayed.\nThere was no message available.", msg); } // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }