public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("JetStream Publish Vs Core Publish", args, Usage) .DefaultStream("js-or-core-stream") .DefaultSubject("js-or-core-subject") .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 a JetStream context IJetStream js = c.CreateJetStreamContext(); // Regular Nats publish is straightforward c.Publish(helper.Subject, Encoding.ASCII.GetBytes("regular-message")); // A JetStream publish allows you to set publish options // that a regular publish does not. // A JetStream publish returns an ack of the publish. There // is no ack in a regular message. Msg msg = new Msg(helper.Subject, Encoding.ASCII.GetBytes("js-message")); PublishAck pa = js.Publish(msg); Console.WriteLine(pa); // set up the subscription IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(helper.Subject); c.Flush(500); // flush outgoing communication with/to the server // Both messages appear in the stream as JetStream messages msg = sub.NextMessage(500); msg.Ack(); Console.WriteLine("Received Data: '" + Encoding.ASCII.GetString(msg.Data) + "'\n Meta: " + msg.MetaData); msg = sub.NextMessage(500); msg.Ack(); Console.WriteLine("Received Data: '" + Encoding.ASCII.GetString(msg.Data) + "'\n Meta: " + msg.MetaData); // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
// ---------------------------------------------------------------------------------------------------- // READ MESSAGES // ---------------------------------------------------------------------------------------------------- public static IList <Msg> ReadMessagesAck(ISyncSubscription sub, bool verbose = true, int timeout = 1000) { if (verbose) { Console.Write("Read/Ack ->"); } IList <Msg> messages = new List <Msg>(); bool keepGoing = true; while (keepGoing) { try { Msg msg = sub.NextMessage(timeout); messages.Add(msg); msg.Ack(); if (verbose) { Console.Write(" " + msg.Subject + " / " + Encoding.UTF8.GetString(msg.Data)); } } catch (NATSTimeoutException) // timeout means there are no messages available { keepGoing = false; } } if (verbose) { Console.Write(messages.Count == 0 ? " No messages available <-\n" : " <-\n"); } return(messages); }
public void TestAckNak() { 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 // NAK JsPublish(js, SUBJECT, "NAK", 1); sub.Pull(1); Msg message = sub.NextMessage(1000); Assert.NotNull(message); Assert.Equal("NAK1", Encoding.ASCII.GetString(message.Data)); message.Nak(); sub.Pull(1); message = sub.NextMessage(1000); Assert.NotNull(message); Assert.Equal("NAK1", Encoding.ASCII.GetString(message.Data)); message.Ack(); sub.Pull(1); AssertNoMoreMessages(sub); }); }
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 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 Run() { while (allReceived.Read() < msgCount) { try { Msg msg = sub.NextMessage(500); received++; allReceived.Increment(); datas.Add(Encoding.UTF8.GetString(msg.Data)); msg.Ack(); } catch (NATSTimeoutException) { // timeout is acceptable, means no messages available. } } }
public static IList <Msg> ReadMessagesAck(ISyncSubscription sub) { IList <Msg> messages = new List <Msg>(); try { Msg msg = sub.NextMessage(DefaultTimeout); while (msg != null) { messages.Add(msg); msg.Ack(); msg = sub.NextMessage(DefaultTimeout); } } catch (NATSTimeoutException) { // it's fine, just end } return(messages); }
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 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); } }
private static void _ack(Stats stats, Msg m) { stats.Start(); m.Ack(); stats.Stop(); }
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 static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("NATS JetStream Push Subscribe Bind Durable", args, Usage) .DefaultStream("example-stream") .DefaultSubject("example-subject") .DefaultDurable("bind-durable") .DefaultDeliverSubject("bind-deliver") .DefaultCount(0, true) // true indicated 0 means unlimited .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); // The durable consumer must already exist. Usually it would be made in configuration // or via the NATS CLI but we are making it here. // Important: The consumer must have a deliver subject when made this way or it will be // understood to be a pull consumer by the server. // NOTE: If you ran this example already, the consumer will have been created // This is not a problem if it is exactly the same. Most ConsumerConfiguration // properties are not modifiable once created. ConsumerConfiguration cc = ConsumerConfiguration.Builder() .WithDurable(helper.Durable) .WithDeliverSubject(helper.DeliverSubject) .Build(); c.CreateJetStreamManagementContext().AddOrUpdateConsumer(helper.Stream, cc); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // bind subscribe to the stream - either variety will work // V1. Version designed specifically for this purpose. PushSubscribeOptions so = PushSubscribeOptions.BindTo(helper.Stream, helper.Durable); // V2. optional long form // PushSubscribeOptions so = PushSubscribeOptions.Builder() // .WithBind(true) // .WithStream(helper.Stream) // .WithDurable(helper.Durable) // .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 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); } }