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 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 JsQueueSubscriber(int msgCount, IJetStream js, IJetStreamPushSyncSubscription sub, InterlockedLong allReceived) { this.msgCount = msgCount; this.js = js; this.sub = sub; this.allReceived = allReceived; received = 0; datas = new List <string>(); }
private static void _subPullFetch(Context ctx, Stats stats, IJetStreamPullSubscription sub, int id, string counterKey) { int rcvd = 0; Msg lastUnAcked = null; int unAckedCount = 0; int unReported = 0; string label = ctx.GetLabel(id); InterlockedLong counter = ctx.GetSubscribeCounter(counterKey); while (counter.Read() < ctx.MessageCount) { stats.Start(); IList <Msg> list = sub.Fetch(ctx.BatchSize, 500); long hold = stats.Elapsed(); long received = DateTimeOffset.Now.ToUnixTimeMilliseconds(); int lc = list.Count; if (lc > 0) { foreach (Msg m in list) { stats.Count(m, received); counter.Increment(); if ((lastUnAcked = AckMaybe(ctx, stats, m, ++unAckedCount)) == null) { unAckedCount = 0; } } rcvd += lc; unReported = ReportMaybe(label, ctx, rcvd, unReported + lc, "Messages Read"); } AcceptHoldOnceStarted(label, stats, rcvd, hold); } if (lastUnAcked != null) { _ack(stats, lastUnAcked); } Report(label, rcvd, "Finished Reading Messages"); }
private static void SubPush(Context ctx, IConnection c, Stats stats, int id) { IJetStream js = c.CreateJetStreamContext(ctx.GetJetStreamOptions()); IJetStreamPushSyncSubscription sub; if (ctx.Action.IsQueue) { // if we don't do this, multiple threads will try to make the same consumer because // when they start, the consumer does not exist. So force them do it one at a time. lock (QueueLock) { sub = js.PushSubscribeSync(ctx.Subject, ctx.QueueName, ConsumerConfiguration.Builder() .WithAckPolicy(ctx.AckPolicy) .WithAckWait(Duration.OfSeconds(ctx.AckWaitSeconds)) .WithDeliverGroup(ctx.QueueName) .BuildPushSubscribeOptions()); } } else { sub = js.PushSubscribeSync(ctx.Subject, ConsumerConfiguration.Builder() .WithAckPolicy(ctx.AckPolicy) .WithAckWait(Duration.OfSeconds(ctx.AckWaitSeconds)) .BuildPushSubscribeOptions()); } int rcvd = 0; Msg lastUnAcked = null; int unAckedCount = 0; int unReported = 0; string label = ctx.GetLabel(id); InterlockedLong counter = ctx.GetSubscribeCounter(ctx.GetSubDurable(id)); while (counter.Read() < ctx.MessageCount) { try { stats.Start(); Msg m = sub.NextMessage(1000); long hold = stats.Elapsed(); long received = DateTimeOffset.Now.ToUnixTimeMilliseconds(); stats.AcceptHold(hold); stats.Count(m, received); counter.Increment(); if ((lastUnAcked = AckMaybe(ctx, stats, m, ++unAckedCount)) == null) { unAckedCount = 0; } unReported = ReportMaybe(label, ctx, ++rcvd, ++unReported, "Messages Read"); } catch (NATSTimeoutException) { // normal timeout long hold = stats.Elapsed(); AcceptHoldOnceStarted(label, stats, rcvd, hold); } } if (lastUnAcked != null) { _ack(stats, lastUnAcked); } Report(label, rcvd, "Finished Reading Messages"); }