public void TestNoWait() { Context.RunInJsServer(c => { // create the stream. CreateDefaultTestStream(c); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Build our subscription options. Durable is REQUIRED for pull based subscriptions PullSubscribeOptions options = PullSubscribeOptions.Builder().WithDurable(DURABLE).Build(); // Pull Subscribe. IJetStreamPullSubscription sub = js.PullSubscribe(SUBJECT, options); AssertSubscription(sub, STREAM, DURABLE, null, true); c.Flush(DefaultTimeout); // flush outgoing communication with/to the server // publish 10 messages // no wait, batch size 10, there are 10 messages, we will read them all and not trip nowait JsPublish(js, SUBJECT, "A", 10); sub.PullNoWait(10); IList <Msg> messages = ReadMessagesAck(sub); Assert.Equal(10, messages.Count); AssertAllJetStream(messages); // publish 20 messages // no wait, batch size 10, there are 20 messages, we will read 10 JsPublish(js, SUBJECT, "B", 20); sub.PullNoWait(10); messages = ReadMessagesAck(sub); Assert.Equal(10, messages.Count); // there are still ten messages // no wait, batch size 10, there are 20 messages, we will read 10 sub.PullNoWait(10); messages = ReadMessagesAck(sub); Assert.Equal(10, messages.Count); // publish 5 messages // no wait, batch size 10, there are 5 messages, we WILL trip nowait JsPublish(js, SUBJECT, "C", 5); sub.PullNoWait(10); messages = ReadMessagesAck(sub); Assert.Equal(5, messages.Count); // publish 12 messages // no wait, batch size 10, there are more than batch messages we will read 10 JsPublish(js, SUBJECT, "D", 12); sub.PullNoWait(10); messages = ReadMessagesAck(sub); Assert.Equal(10, messages.Count); // 2 messages left // no wait, less than batch size will WILL trip nowait sub.PullNoWait(10); messages = ReadMessagesAck(sub); Assert.Equal(2, messages.Count); }); }
private void ChangeExPull(IJetStream js, ConsumerConfiguration.ConsumerConfigurationBuilder builder, String changedField) { NATSJetStreamClientException e = Assert.Throws <NATSJetStreamClientException>( () => js.PullSubscribe(SUBJECT, PullSubscribeOptions.Builder().WithConfiguration(builder.Build()).Build())); _ChangeEx(e, changedField); }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("Pull Subscription using primitive Expires In", args, Usage) .DefaultStream("fetch-stream") .DefaultSubject("fetch-subject") .DefaultDurable("fetch-durable") .DefaultCount(15) .Build(); 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, helper.Subject); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Start publishing the messages, don't wait for them to finish, simulating an outside producer. JsUtils.PublishInBackground(js, helper.Subject, "fetch-message", helper.Count); // Build our consumer configuration and subscription options. // make sure the ack wait is sufficient to handle the reading and processing of the batch. // Durable is REQUIRED for pull based subscriptions ConsumerConfiguration cc = ConsumerConfiguration.Builder() .WithAckWait(2500) .Build(); PullSubscribeOptions pullOptions = PullSubscribeOptions.Builder() .WithDurable(helper.Durable) // required .WithConfiguration(cc) .Build(); // subscribe IJetStreamPullSubscription sub = js.PullSubscribe(helper.Subject, pullOptions); c.Flush(1000); int red = 0; while (red < helper.Count) { IList <Msg> list = sub.Fetch(10, 1000); foreach (Msg m in list) { Console.WriteLine($"{++red}. Message: {m}"); m.Ack(); } } // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
public void TestAckTerm() { Context.RunInJsServer(c => { // create the stream. CreateDefaultTestStream(c); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Build our subscription options. Durable is REQUIRED for pull based subscriptions PullSubscribeOptions options = PullSubscribeOptions.Builder().WithDurable(DURABLE).Build(); IJetStreamPullSubscription sub = js.PullSubscribe(SUBJECT, options); c.Flush(DefaultTimeout); // flush outgoing communication with/to the server // TERM JsPublish(js, SUBJECT, "TERM", 1); sub.Pull(1); Msg message = sub.NextMessage(1000); Assert.NotNull(message); Assert.Equal("TERM1", Encoding.ASCII.GetString(message.Data)); message.Term(); sub.Pull(1); AssertNoMoreMessages(sub); }); }
public void TestDurable() { Context.RunInJsServer(c => { // create the stream. CreateDefaultTestStream(c); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Build our subscription options normally PullSubscribeOptions options1 = PullSubscribeOptions.Builder().WithDurable(DURABLE).Build(); _testDurable(js, () => js.PullSubscribe(SUBJECT, options1)); // bind long form PullSubscribeOptions options2 = PullSubscribeOptions.Builder() .WithStream(STREAM) .WithDurable(DURABLE) .WithBind(true) .Build(); _testDurable(js, () => js.PullSubscribe(null, options2)); // bind short form PullSubscribeOptions options3 = PullSubscribeOptions.BindTo(STREAM, DURABLE); _testDurable(js, () => js.PullSubscribe(null, options3)); }); }
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 TestPullAffirmative() { PullSubscribeOptions so = PullSubscribeOptions.Builder() .WithStream(STREAM) .WithDurable(DURABLE) .Build(); Assert.Equal(STREAM, so.Stream); Assert.Equal(DURABLE, so.Durable); Assert.True(so.Pull); }
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 TestGetConsumerInfoFromSubscription() { Context.RunInJsServer(c => { CreateDefaultTestStream(c); IJetStream js = c.CreateJetStreamContext(); IJetStreamPushSyncSubscription psync = js.PushSubscribeSync(SUBJECT); ConsumerInfo ci = psync.GetConsumerInformation(); Assert.Equal(STREAM, ci.Stream); PullSubscribeOptions pso = PullSubscribeOptions.Builder().WithDurable(DURABLE).Build(); IJetStreamPullSubscription pull = js.PullSubscribe(SUBJECT, pso); ci = pull.GetConsumerInformation(); Assert.Equal(STREAM, ci.Stream); }); }
public void TestBindPull() { Context.RunInJsServer(c => { CreateDefaultTestStream(c); IJetStream js = c.CreateJetStreamContext(); JsPublish(js, SUBJECT, 1, 1); PullSubscribeOptions pso = PullSubscribeOptions.Builder() .WithDurable(DURABLE) .Build(); IJetStreamPullSubscription s = js.PullSubscribe(SUBJECT, pso); s.Pull(1); Msg m = s.NextMessage(1000); Assert.NotNull(m); Assert.Equal(Data(1), Encoding.ASCII.GetString(m.Data)); m.Ack(); s.Unsubscribe(); JsPublish(js, SUBJECT, 2, 1); pso = PullSubscribeOptions.Builder() .WithStream(STREAM) .WithDurable(DURABLE) .WithBind(true) .Build(); s = js.PullSubscribe(SUBJECT, pso); s.Pull(1); m = s.NextMessage(1000); Assert.NotNull(m); Assert.Equal(Data(2), Encoding.ASCII.GetString(m.Data)); m.Ack(); s.Unsubscribe(); JsPublish(js, SUBJECT, 3, 1); pso = PullSubscribeOptions.BindTo(STREAM, DURABLE); s = js.PullSubscribe(SUBJECT, pso); s.Pull(1); m = s.NextMessage(1000); Assert.NotNull(m); Assert.Equal(Data(3), Encoding.ASCII.GetString(m.Data)); }); }
public void TestPullValidation() { PullSubscribeOptions.PullSubscribeOptionsSubscribeOptionsBuilder builder1 = PullSubscribeOptions.Builder(); Assert.Throws <ArgumentException>(() => builder1.WithStream(HasDot).Build()); Assert.Throws <ArgumentException>(() => builder1.WithDurable(HasDot).Build()); ConsumerConfiguration ccBadDur = ConsumerConfiguration.Builder().WithDurable(HasDot).Build(); Assert.Throws <ArgumentException>(() => builder1.WithConfiguration(ccBadDur).Build()); // durable directly PullSubscribeOptions.Builder().WithDurable(DURABLE).Build(); // in configuration ConsumerConfiguration cc = ConsumerConfiguration.Builder().WithDurable(DURABLE).Build(); PullSubscribeOptions.Builder().WithConfiguration(cc).Build(); // new helper ConsumerConfiguration.Builder().WithDurable(DURABLE).BuildPullSubscribeOptions(); }
public void TestAckWaitTimeout() { Context.RunInJsServer(c => { // create the stream. CreateDefaultTestStream(c); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); ConsumerConfiguration cc = ConsumerConfiguration.Builder() .WithAckWait(1500) .Build(); PullSubscribeOptions pso = PullSubscribeOptions.Builder() .WithDurable(DURABLE) .WithConfiguration(cc) .Build(); IJetStreamPullSubscription sub = js.PullSubscribe(SUBJECT, pso); c.Flush(DefaultTimeout); // flush outgoing communication with/to the server // Ack Wait timeout JsPublish(js, SUBJECT, "WAIT", 1); sub.Pull(1); Msg message = sub.NextMessage(1000); Assert.NotNull(message); Assert.Equal("WAIT1", Encoding.ASCII.GetString(message.Data)); Thread.Sleep(2000); sub.Pull(1); message = sub.NextMessage(1000); Assert.NotNull(message); Assert.Equal("WAIT1", Encoding.ASCII.GetString(message.Data)); sub.Pull(1); AssertNoMoreMessages(sub); }); }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("Pull Subscription using primitive Expires In", args, Usage) .DefaultStream("fetch-uc-stream") .DefaultSubject("fetch-uc-subject") .DefaultDurable("fetch-uc-durable") .DefaultCount(15) .Build(); 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, helper.Subject); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Build our consumer configuration and subscription options. // make sure the ack wait is sufficient to handle the reading and processing of the batch. // Durable is REQUIRED for pull based subscriptions ConsumerConfiguration cc = ConsumerConfiguration.Builder() .WithAckWait(2500) .Build(); PullSubscribeOptions pullOptions = PullSubscribeOptions.Builder() .WithDurable(helper.Durable) // required .WithConfiguration(cc) .Build(); // 0.1 Initialize. subscription // 0.2 Flush outgoing communication with/to the server, useful when app is both JsUtils.Publishing and subscribing. Console.WriteLine("\n----------\n0. Initialize the subscription and pull."); IJetStreamPullSubscription sub = js.PullSubscribe(helper.Subject, pullOptions); c.Flush(1000); // 1. Fetch, but there are no messages yet. // - Read the messages, get them all (0) Console.WriteLine("----------\n1. There are no messages yet"); IList <Msg> messages = sub.Fetch(10, 3000); JsUtils.Report(messages); foreach (Msg m in messages) { m.Ack(); } Console.WriteLine("We should have received 0 total messages, we received: " + messages.Count); // 2. Publish 10 messages // - Fetch messages, get 10 Console.WriteLine("----------\n2. Publish 10 which satisfies the batch"); JsUtils.Publish(js, helper.Subject, "A", 10); messages = sub.Fetch(10, 3000); JsUtils.Report(messages); foreach (Msg m in messages) { m.Ack(); } Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 3. Publish 20 messages // - Fetch messages, only get 10 Console.WriteLine("----------\n3. Publish 20 which is larger than the batch size."); JsUtils.Publish(js, helper.Subject, "B", 20); messages = sub.Fetch(10, 3000); JsUtils.Report(messages); foreach (Msg m in messages) { m.Ack(); } Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 4. There are still messages left from the last // - Fetch messages, get 10 Console.WriteLine("----------\n4. Get the rest of the JsUtils.Publish."); messages = sub.Fetch(10, 3000); JsUtils.Report(messages); foreach (Msg m in messages) { m.Ack(); } Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 5. Publish 5 messages // - Fetch messages, get 5 // - Since there are less than batch size we only get what the server has. Console.WriteLine("----------\n5. Publish 5 which is less than batch size."); JsUtils.Publish(js, helper.Subject, "C", 5); messages = sub.Fetch(10, 3000); JsUtils.Report(messages); foreach (Msg m in messages) { m.Ack(); } Console.WriteLine("We should have received 5 total messages, we received: " + messages.Count); // 6. Publish 15 messages // - Fetch messages, only get 10 Console.WriteLine("----------\n6. Publish 15 which is more than the batch size."); JsUtils.Publish(js, helper.Subject, "D", 15); messages = sub.Fetch(10, 3000); JsUtils.Report(messages); foreach (Msg m in messages) { m.Ack(); } Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 7. There are 5 messages left // - Fetch messages, only get 5 Console.WriteLine("----------\n7. There are 5 messages left."); messages = sub.Fetch(10, 3000); JsUtils.Report(messages); foreach (Msg m in messages) { m.Ack(); } Console.WriteLine("We should have received 5 messages, we received: " + messages.Count); // 8. Read but don't ack. // - Fetch messages, get 10, but either take too long to ack them or don't ack them Console.WriteLine("----------\n8. Fetch but don't ack."); JsUtils.Publish(js, helper.Subject, "E", 10); messages = sub.Fetch(10, 3000); JsUtils.Report(messages); Console.WriteLine("We should have received 10 message, we received: " + messages.Count); Thread.Sleep(3000); // longer than the ackWait // 9. Fetch messages, // - get the 10 messages we didn't ack Console.WriteLine("----------\n9. Fetch, get the messages we did not ack."); messages = sub.Fetch(10, 3000); JsUtils.Report(messages); foreach (Msg m in messages) { m.Ack(); } Console.WriteLine("We should have received 10 message, we received: " + messages.Count); Console.WriteLine("----------\n"); // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("Pull Subscription using primitive Expires In, Use Cases", args, Usage) .DefaultStream("expires-in-uc-stream") .DefaultSubject("expires-in-uc-subject") .DefaultDurable("expires-in-uc-durable") .Build(); 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, helper.Subject); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Build our subscription options. Durable is REQUIRED for pull based subscriptions PullSubscribeOptions pullOptions = PullSubscribeOptions.Builder() .WithDurable(helper.Durable) // required .Build(); // 0.1 Initialize. subscription // 0.2 Flush outgoing communication with/to the server, useful when app is both JsUtils.Publishing and subscribing. // 0.3 Start the pull, you don't have to call this again because AckMode.NEXT // - When we ack a batch message the server starts preparing or adding to the next batch. Console.WriteLine("\n----------\n0. Initialize the subscription and pull."); IJetStreamPullSubscription sub = js.PullSubscribe(helper.Subject, pullOptions); c.Flush(1000); // 1. Publish some that is less than the batch size. Console.WriteLine("\n----------\n1. Publish some amount of messages, but not entire batch size."); JsUtils.Publish(js, helper.Subject, "A", 6); sub.PullExpiresIn(10, 1200); IList <Msg> messages = JsUtils.ReadMessagesAck(sub, timeout: 2000); Console.WriteLine("We should have received 6 total messages, we received: " + messages.Count); // 2. Publish some more covering our pull size... Console.WriteLine("----------\n2. Publish more than the batch size."); sub.PullExpiresIn(10, 1200); JsUtils.Publish(js, helper.Subject, "B", 14); messages = JsUtils.ReadMessagesAck(sub, timeout: 2000); Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 3. There are still 4 messages from B, but the batch was finished // - won't get any messages until a pull is issued. Console.WriteLine("----------\n3. Read without issuing a pull."); messages = JsUtils.ReadMessagesAck(sub, timeout: 2000); Console.WriteLine("We should have received 0 total messages, we received: " + messages.Count); // 4. re-issue the pull to get the last 4 Console.WriteLine("----------\n4. Issue the pull to get the last 4."); sub.PullExpiresIn(10, 1200); messages = JsUtils.ReadMessagesAck(sub, timeout: 2000); Console.WriteLine("We should have received 4 total messages, we received: " + messages.Count); // 5. publish a lot of messages Console.WriteLine("----------\n5. Publish a lot of messages. The last pull was under the batch size."); Console.WriteLine(" Issue another pull with batch size less than number of messages."); JsUtils.Publish(js, helper.Subject, "C", 25); sub.PullExpiresIn(10, 1200); messages = JsUtils.ReadMessagesAck(sub, timeout: 2000); Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 6. there are still more messages Console.WriteLine("----------\n6. Still more messages. Issue another pull with batch size less than number of messages."); sub.PullExpiresIn(10, 1200); messages = JsUtils.ReadMessagesAck(sub, timeout: 2000); Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 7. there are still more messages Console.WriteLine("----------\n7. Still more messages. Issue another pull with batch size more than number of messages."); sub.PullExpiresIn(10, 1200); messages = JsUtils.ReadMessagesAck(sub, timeout: 2000); Console.WriteLine("We should have received 5 total messages, we received: " + messages.Count); // 8. we got them all Console.WriteLine("----------\n8. No messages left."); sub.PullExpiresIn(10, 1200); messages = JsUtils.ReadMessagesAck(sub, timeout: 2000); Console.WriteLine("We should have received 0 total messages, we received: " + messages.Count); Console.WriteLine("----------\n"); // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("Pull Subscription using primitive No Wait, Use Cases", args, Usage) .DefaultStream("nowait-uc-stream") .DefaultSubject("nowait-uc-subject") .DefaultDurable("nowait-uc-durable") .Build(); 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, helper.Subject); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Build our subscription options. Durable is REQUIRED for pull based subscriptions PullSubscribeOptions pullOptions = PullSubscribeOptions.Builder() .WithDurable(helper.Durable) // required .Build(); // 0.1 Initialize. subscription // 0.2 DO NOT start the pull, no wait works differently than regular pull. // With no wait, we have to start the pull the first time and every time the // batch size is exhausted or no waits out. // 0.3 Flush outgoing communication with/to the server, useful when app is both publishing and subscribing. Console.WriteLine("\n----------\n0. Initialize the subscription and pull."); IJetStreamPullSubscription sub = js.PullSubscribe(helper.Subject, pullOptions); c.Flush(1000); // 1. Start the pull, but there are no messages yet. // - Read the messages // - Since there are less than the batch size, we get them all (0) Console.WriteLine("----------\n1. There are no messages yet"); sub.PullNoWait(10); IList <Msg> messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 0 total messages, we received: " + messages.Count); // 2. Publish 10 messages // - Start the pull // - Read the messages // - Since there are exactly the batch size we get them all Console.WriteLine("----------\n2. Publish 10 which satisfies the batch"); JsUtils.Publish(js, helper.Subject, "A", 10); sub.PullNoWait(10); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 3. Publish 20 messages // - Start the pull // - Read the messages Console.WriteLine("----------\n3. Publish 20 which is larger than the batch size."); JsUtils.Publish(js, helper.Subject, "B", 20); sub.PullNoWait(10); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 4. There are still messages left from the last // - Start the pull // - Read the messages Console.WriteLine("----------\n4. Get the rest of the publish."); sub.PullNoWait(10); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 5. Publish 5 messages // - Start the pull // - Read the messages Console.WriteLine("----------\n5. Publish 5 which is less than batch size."); JsUtils.Publish(js, helper.Subject, "C", 5); sub.PullNoWait(10); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 5 total messages, we received: " + messages.Count); // 6. Publish 14 messages // - Start the pull // - Read the messages // - we do NOT get a nowait status message if there are more or equals messages than the batch Console.WriteLine("----------\n6. Publish 14 which is more than the batch size."); JsUtils.Publish(js, helper.Subject, "D", 14); sub.PullNoWait(10); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 7. There are 4 messages left // - Start the pull // - Read the messages // - Since there are less than batch size the last message we get will be a status 404 message. Console.WriteLine("----------\n7. There are 4 messages left, which is less than the batch size."); sub.PullNoWait(10); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 4 messages, we received: " + messages.Count); Console.WriteLine("----------\n"); // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
public void TestBasic() { Context.RunInJsServer(c => { // create the stream. CreateDefaultTestStream(c); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Build our subscription options. Durable is REQUIRED for pull based subscriptions PullSubscribeOptions options = PullSubscribeOptions.Builder().WithDurable(DURABLE).Build(); // Pull Subscribe. IJetStreamPullSubscription sub = js.PullSubscribe(SUBJECT, options); AssertSubscription(sub, STREAM, DURABLE, null, true); c.Flush(DefaultTimeout); // flush outgoing communication with/to the server // publish some amount of messages, but not entire pull size JsPublish(js, SUBJECT, "A", 4); // start the pull sub.Pull(10); // read what is available, expect 4 IList <Msg> messages = ReadMessagesAck(sub); int total = messages.Count; ValidateRedAndTotal(4, messages.Count, 4, total); // publish some more covering our initial pull and more JsPublish(js, SUBJECT, "B", 10); // read what is available, expect 6 more messages = ReadMessagesAck(sub); total += messages.Count; ValidateRedAndTotal(6, messages.Count, 10, total); // read what is available, should be zero since we didn't re-pull messages = ReadMessagesAck(sub); total += messages.Count; ValidateRedAndTotal(0, messages.Count, 10, total); // re-issue the pull sub.Pull(10); // read what is available, should be 4 left over messages = ReadMessagesAck(sub); total += messages.Count; ValidateRedAndTotal(4, messages.Count, 14, total); // publish some more JsPublish(js, SUBJECT, "C", 10); // read what is available, should be 6 since we didn't finish the last batch messages = ReadMessagesAck(sub); total += messages.Count; ValidateRedAndTotal(6, messages.Count, 20, total); // re-issue the pull, but a smaller amount sub.Pull(2); // read what is available, should be 5 since we changed the pull size messages = ReadMessagesAck(sub); total += messages.Count; ValidateRedAndTotal(2, messages.Count, 22, total); // re-issue the pull, since we got the full batch size sub.Pull(2); // read what is available, should be zero since we didn't re-pull messages = ReadMessagesAck(sub); total += messages.Count; ValidateRedAndTotal(2, messages.Count, 24, total); // re-issue the pull, any amount there are no messages sub.Pull(1); // read what is available, there are none messages = ReadMessagesAck(sub); total += messages.Count; ValidateRedAndTotal(0, messages.Count, 24, total); }); }
public void TestPullExpires() { Context.RunInJsServer(c => { // create the stream. CreateDefaultTestStream(c); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Build our subscription options. Durable is REQUIRED for pull based subscriptions PullSubscribeOptions options = PullSubscribeOptions.Builder().WithDurable(DURABLE).Build(); // Subscribe synchronously. IJetStreamPullSubscription sub = js.PullSubscribe(SUBJECT, options); AssertSubscription(sub, STREAM, DURABLE, null, true); c.Flush(DefaultTimeout); // flush outgoing communication with/to the server int expires = 250; // millis // publish 10 messages JsPublish(js, SUBJECT, "A", 5); sub.PullExpiresIn(10, expires); IList <Msg> messages = ReadMessagesAck(sub); Assert.Equal(5, messages.Count); AssertAllJetStream(messages); Thread.Sleep(expires); // make sure the pull actually expires JsPublish(js, SUBJECT, "B", 10); sub.PullExpiresIn(10, expires); messages = ReadMessagesAck(sub); Assert.Equal(10, messages.Count); Thread.Sleep(expires); // make sure the pull actually expires JsPublish(js, SUBJECT, "C", 5); sub.PullExpiresIn(10, expires); messages = ReadMessagesAck(sub); Assert.Equal(5, messages.Count); AssertAllJetStream(messages); Thread.Sleep(expires); // make sure the pull actually expires JsPublish(js, SUBJECT, "D", 10); sub.Pull(10); messages = ReadMessagesAck(sub); Assert.Equal(10, messages.Count); JsPublish(js, SUBJECT, "E", 5); sub.PullExpiresIn(10, expires); // using millis version here messages = ReadMessagesAck(sub); Assert.Equal(5, messages.Count); AssertAllJetStream(messages); Thread.Sleep(expires); // make sure the pull actually expires JsPublish(js, SUBJECT, "F", 10); sub.PullNoWait(10); messages = ReadMessagesAck(sub); Assert.Equal(10, messages.Count); JsPublish(js, SUBJECT, "G", 5); sub.PullExpiresIn(10, expires); // using millis version here messages = ReadMessagesAck(sub); Assert.Equal(5, messages.Count); AssertAllJetStream(messages); JsPublish(js, SUBJECT, "H", 10); messages = sub.Fetch(10, expires); Assert.Equal(10, messages.Count); AssertAllJetStream(messages); JsPublish(js, SUBJECT, "I", 5); sub.PullExpiresIn(10, expires); messages = ReadMessagesAck(sub); Assert.Equal(5, messages.Count); AssertAllJetStream(messages); Thread.Sleep(expires); // make sure the pull actually expires }); }
public void TestFetch() { Console.SetOut(new ConsoleWriter(output)); Context.RunInJsServer(c => { // create the stream. CreateDefaultTestStream(c); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); int fetchMs = 3000; int ackWaitMs = fetchMs * 2; ConsumerConfiguration cc = ConsumerConfiguration.Builder() .WithAckWait(ackWaitMs) .Build(); PullSubscribeOptions options = PullSubscribeOptions.Builder() .WithDurable(DURABLE) .WithConfiguration(cc) .Build(); IJetStreamPullSubscription sub = js.PullSubscribe(SUBJECT, options); AssertSubscription(sub, STREAM, DURABLE, null, true); c.Flush(DefaultTimeout); // flush outgoing communication with/to the server IList <Msg> messages = sub.Fetch(10, fetchMs); ValidateRead(0, messages.Count); AckAll(messages); Thread.Sleep(ackWaitMs); // let the pull expire JsPublish(js, SUBJECT, "A", 10); messages = sub.Fetch(10, fetchMs); ValidateRead(10, messages.Count); AckAll(messages); JsPublish(js, SUBJECT, "B", 20); messages = sub.Fetch(10, fetchMs); ValidateRead(10, messages.Count); AckAll(messages); messages = sub.Fetch(10, fetchMs); ValidateRead(10, messages.Count); AckAll(messages); JsPublish(js, SUBJECT, "C", 5); messages = sub.Fetch(10, fetchMs); ValidateRead(5, messages.Count); AckAll(messages); Thread.Sleep(fetchMs * 2); // let the pull expire JsPublish(js, SUBJECT, "D", 15); messages = sub.Fetch(10, fetchMs); ValidateRead(10, messages.Count); AckAll(messages); messages = sub.Fetch(10, fetchMs); ValidateRead(5, messages.Count); AckAll(messages); JsPublish(js, SUBJECT, "E", 10); messages = sub.Fetch(10, fetchMs); ValidateRead(10, messages.Count); Thread.Sleep(ackWaitMs); messages = sub.Fetch(10, fetchMs); ValidateRead(10, messages.Count); AckAll(messages); }); }
private void ChangeOkPull(IJetStream js, ConsumerConfiguration.ConsumerConfigurationBuilder builder) { js.PullSubscribe(SUBJECT, PullSubscribeOptions.Builder().WithConfiguration(builder.Build()).Build()).Unsubscribe(); }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("Pull Subscription using primitive Expires In", args, Usage) .DefaultStream("expires-in-stream") .DefaultSubject("expires-in-subject") .DefaultDurable("expires-in-durable") .DefaultCount(15) .Build(); 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, helper.Subject); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Start publishing the messages, don't wait for them to finish, simulating an outside producer. JsUtils.PublishInBackground(js, helper.Subject, "expires-in-message", helper.Count); // Build our subscription options. Durable is REQUIRED for pull based subscriptions PullSubscribeOptions pullOptions = PullSubscribeOptions.Builder() .WithDurable(helper.Durable) // required .Build(); // subscribe IJetStreamPullSubscription sub = js.PullSubscribe(helper.Subject, pullOptions); c.Flush(1000); bool keepGoing = true; int red = 0; while (keepGoing && red < helper.Count) { sub.PullExpiresIn(10, 1000); int round = 0; while (keepGoing && round < 10) { try { Msg m = sub.NextMessage(1000); // first message Console.WriteLine($"{++red}. Message: {m}"); m.Ack(); round++; } catch (NATSTimeoutException) // timeout means there are no messages available { keepGoing = false; } } } // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } 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("Pull Subscription using primitive Batch Size, Use Cases", args, Usage) .DefaultStream("pull-stream") .DefaultSubject("pull-subject") .DefaultDurable("pull-durable") .Build(); 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, helper.Subject); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Build our subscription options. Durable is REQUIRED for pull based subscriptions PullSubscribeOptions pullOptions = PullSubscribeOptions.Builder() .WithDurable(helper.Durable) // required .Build(); // 0.1 Initialize. subscription // 0.2 Flush outgoing communication with/to the server, useful when app is both JsUtils.Publishing and subscribing. // 0.3 Start the pull, you don't have to call this again because AckMode.NEXT // - When we ack a batch message the server starts preparing or adding to the next batch. Console.WriteLine("\n----------\n0. Initialize the subscription and pull."); IJetStreamPullSubscription sub = js.PullSubscribe(helper.Subject, pullOptions); c.Flush(1000); sub.Pull(10); // 1. JsUtils.Publish some that is less than the batch size. // - Do this first as data will typically be published first. Console.WriteLine("----------\n1. JsUtils.Publish some amount of messages, but not entire batch size."); JsUtils.Publish(js, helper.Subject, "A", 4); IList <Msg> messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 4 total messages, we received: " + messages.Count); // 2. JsUtils.Publish some more covering our pull size... // - Read what is available, expect only 6 b/c 4 + 6 = 10 Console.WriteLine("----------\n2. JsUtils.Publish more than the remaining batch size."); JsUtils.Publish(js, helper.Subject, "B", 10); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 6 total messages, we received: " + messages.Count); // 3. There are still 4 messages from B, but the batch was finished // - won't get any messages until a pull is issued. Console.WriteLine("----------\n3. Read without re-issue."); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 0 total messages, we received: " + messages.Count); // 4. re-issue the pull to get the last 4 Console.WriteLine("----------\n4. Re-issue to get the last 4."); sub.Pull(10); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 4 total messages, we received: " + messages.Count); Console.WriteLine("----------\n"); // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }