예제 #1
0
        public void Client()
        {
            string projectId = _fixture.ProjectId;
            string topicId   = _fixture.CreateTopicId();

            // Sample: ClientWide
            // Create a default PublisherServiceApiSettings, with a custom header for calls to all RPC methods.
            PublisherServiceApiSettings publisherSettings = new PublisherServiceApiSettings
            {
                CallSettings = new CallSettings(null, null, null, metadata => metadata.Add("ClientVersion", "1.0.0"), null, null)
            };
            PublisherServiceApiClient client = PublisherServiceApiClient.Create(settings: publisherSettings);
            // Create a topic name from the projectId and topicId.
            TopicName topicName = new TopicName(projectId, topicId);
            // The custom 'ClientVersion' header will be included in the RPC call, due to
            // the client being configured with 'publishersettings' above.
            Topic topic = client.CreateTopic(topicName);
            // End sample
        }
예제 #2
0
        public void ClientPerMethod()
        {
            string projectId = _fixture.ProjectId;
            string topicId   = _fixture.CreateTopicId();

            // Sample: ClientPerMethod
            // Create a default PublisherServiceApiSettings, with a custom header for calls
            // to the CreateTopic RPC method.
            PublisherServiceApiSettings publisherSettings = new PublisherServiceApiSettings();

            publisherSettings.CreateTopicSettings = publisherSettings.CreateTopicSettings.WithHeader("ClientVersion", "1.0.0");
            PublisherServiceApiClient client = PublisherServiceApiClient.Create(settings: publisherSettings);
            // Create a topic name from the projectId and topicId.
            TopicName topicName = new TopicName(projectId, topicId);
            // The custom 'ClientVersion' header will be included in the RPC call, due to
            // the client being configured with 'publishersettings' above.
            Topic topic = client.CreateTopic(topicName);
            // End sample
        }
예제 #3
0
        public void Overrides()
        {
            string            projectId         = _fixture.ProjectId;
            string            topicId           = _fixture.CreateTopicId();
            DateTime          deadline          = DateTime.MaxValue;
            CancellationToken cancellationToken = new CancellationTokenSource().Token;

            // Sample: Overrides
            // Create a default PublisherServiceApiSettings, with customizations for CreateTopic RPCs:
            // * A custom "ClientVersion" header.
            // * A custom 5-second timeout Timing.
            // * No cancellation token.
            PublisherServiceApiSettings publisherSettings = new PublisherServiceApiSettings();

            publisherSettings.CreateTopicSettings = publisherSettings.CreateTopicSettings
                                                    .WithCancellationToken(CancellationToken.None)
                                                    .WithTimeout(TimeSpan.FromSeconds(5))
                                                    .WithHeader("ClientVersion", "1.0.0");

            // Override the above Timing and CancellationToken in the client-wide CallSettings;
            // the Headers are not overridden.
            publisherSettings.CallSettings = CallSettings
                                             .FromExpiration(Expiration.FromDeadline(deadline))
                                             .WithCancellationToken(CancellationToken.None);

            // Create the client with the configured publisherSettings
            PublisherServiceApiClient client = new PublisherServiceApiClientBuilder {
                Settings = publisherSettings
            }.Build();

            // Create a topic name from the projectId and topicId.
            TopicName topicName = new TopicName(projectId, topicId);

            // Call CreateTopic(). Override only the CancellationToken, using a per-RPC-method CallSettings.
            // The CallSettings used during this RPC invocation is:
            // * A custom "ClientVersion" header.
            // * A Timing deadline of 'deadline' (*not* the overridden 5-second timeout).
            // * The CancellationToken 'cancellationToken' (*not* CancellationToken.None).
            Topic topic = client.CreateTopic(topicName, CallSettings.FromCancellationToken(cancellationToken));
            // End sample
        }
예제 #4
0
        private async Task RunBulkMessagingImpl(
            TopicName topicName, SubscriptionName subscriptionName,
            int messageCount, int minMessageSize, int maxMessageSize, int maxMessagesInFlight, int initialNackCount,
            TimeSpan?timeouts          = null, int?cancelAfterRecvCount  = null, TimeSpan?interPublishDelay = null,
            TimeSpan?debugOutputPeriod = null, int?publisherChannelCount = null, int?clientCount            = null)
        {
            // Force messages to be at least 4 bytes long, so an int ID can be used.
            minMessageSize = Math.Max(4, minMessageSize);

            // Create PublisherClient and SubscriberClient
            var publisher = await PublisherClient.CreateAsync(topicName,
                                                              clientCreationSettings : new PublisherClient.ClientCreationSettings(
                                                                  clientCount: publisherChannelCount,
                                                                  publisherServiceApiSettings: timeouts == null ? null : new PublisherServiceApiSettings
            {
                PublishSettings = CallSettings.FromCallTiming(CallTiming.FromRetry(new RetrySettings(
                                                                                       retryBackoff: PublisherServiceApiSettings.GetMessagingRetryBackoff(),
                                                                                       timeoutBackoff: new BackoffSettings(timeouts.Value, timeouts.Value, 1.0),
                                                                                       totalExpiration: Expiration.FromTimeout(timeouts.Value),
                                                                                       retryFilter: PublisherServiceApiSettings.NonIdempotentRetryFilter
                                                                                       )))
            }
                                                                  )).ConfigureAwait(false);

            var subscriber = await SubscriberClient.CreateAsync(subscriptionName,
                                                                clientCreationSettings : new SubscriberClient.ClientCreationSettings(clientCount: clientCount),
                                                                settings : new SubscriberClient.Settings
            {
                AckDeadline         = timeouts,
                FlowControlSettings = new FlowControlSettings(maxMessagesInFlight, null)
            }).ConfigureAwait(false);

            Console.WriteLine("Topic, Subscription, Publisher and Subscriber all created");

            // Subscribe
            int  recvCount = 0;  // Count of received messages
            int  dupCount  = 0;  // Count of duplicate messages
            long recvSum   = 0L; // Sum of bytes of received messages
            var  recvedIds = new ConcurrentDictionary <int, bool>();
            var  nackedIds = new HashSet <int>();
            Task subTask   = subscriber.StartAsync((msg, ct) =>
            {
                int id = BitConverter.ToInt32(msg.Data.ToArray(), 0);
                lock (nackedIds)
                {
                    if (nackedIds.Count < initialNackCount)
                    {
                        if (nackedIds.Add(id))
                        {
                            // This ID not already nacked
                            Interlocked.Increment(ref recvCount);
                            return(Task.FromResult(SubscriberClient.Reply.Nack));
                        }
                    }
                }
                bool wasAdded = recvedIds.TryAdd(id, false);
                if (wasAdded)
                {
                    var localRecvCount = Interlocked.Increment(ref recvCount);
                    Interlocked.Add(ref recvSum, msg.Data.Sum(x => (long)x));
                    if (localRecvCount == cancelAfterRecvCount || localRecvCount >= messageCount + initialNackCount)
                    {
                        // Test finished, so stop subscriber
                        Console.WriteLine("All msgs received, stopping subscriber.");
                        Task unused = subscriber.StopAsync(TimeSpan.FromSeconds(15));
                    }
                }
                else
                {
                    Interlocked.Add(ref dupCount, 1);
                }
                // ACK all messages
                return(Task.FromResult(SubscriberClient.Reply.Ack));
            });

            // Publish
            var  rnd        = new Random(1234);
            var  activePubs = new HashSet <Task>();
            int  sentCount  = 0;
            long sentSum    = 0L; // Sum of bytes of sent messages

            // Watchdog to report progress and fail test on deadlock
            CancellationTokenSource watchdogCts = new CancellationTokenSource();

            Task.Run(async() =>
            {
                var debugOutputPeriod1 = debugOutputPeriod ?? TimeSpan.FromSeconds(1);
                int prevSentCount      = -1;
                int prevRecvCount      = -1;
                int noProgressCount    = 0;
                while (true)
                {
                    await Task.Delay(debugOutputPeriod1, watchdogCts.Token).ConfigureAwait(false);
                    var localSentCount = Interlocked.Add(ref sentCount, 0);
                    var localRecvCount = Interlocked.Add(ref recvCount, 0);
                    var localDupCount  = Interlocked.Add(ref dupCount, 0);
                    if (prevSentCount == localSentCount && prevRecvCount == localRecvCount)
                    {
                        if (noProgressCount > 60)
                        {
                            // Deadlock, shutdown subscriber, and cancel
                            Console.WriteLine("Deadlock detected. Cancelling test");
                            subscriber.StopAsync(new CancellationToken(true));
                            watchdogCts.Cancel();
                            break;
                        }
                        noProgressCount += 1;
                    }
                    else
                    {
                        noProgressCount = 0;
                    }
                    prevSentCount = localSentCount;
                    prevRecvCount = localRecvCount;
                    Console.WriteLine($"[{DateTime.Now}] Sent: {localSentCount} (in-flight: {activePubs.Locked(() => activePubs.Count)}); Recv: {localRecvCount} (dups: {localDupCount})");
                }
            });

            for (int i = 0; i < messageCount; i++)
            {
                if (watchdogCts.IsCancellationRequested)
                {
                    Assert.True(false, "Test cancelled by watchdog");
                }
                if (subTask.IsCompleted)
                {
                    break;
                }
                if (i > 0 && interPublishDelay is TimeSpan delay)
                {
                    await Task.Delay(delay, watchdogCts.Token).ConfigureAwait(false);
                }
                var msgSize = rnd.Next(minMessageSize, maxMessageSize + 1);
                var msg     = new byte[msgSize];
                rnd.NextBytes(msg);
                // Insert an int ID into message
                Array.Copy(BitConverter.GetBytes(i), msg, 4);
                sentSum += msg.Sum(x => (long)x);
                // Send message, and record Task
                var pubTask = publisher.PublishAsync(msg);
                Interlocked.Increment(ref sentCount);
                activePubs.Locked(() => activePubs.Add(pubTask));
                // Remove Task from active when the message has been sent to server
                pubTask.ContinueWith(t => activePubs.Locked(() => activePubs.Remove(pubTask)));
                // If too many messages are currently in flight, wait a bit
                while (activePubs.Locked(() => activePubs.Count) >= maxMessagesInFlight)
                {
                    await Task.Delay(TimeSpan.FromMilliseconds(1)).ConfigureAwait(false);
                }
            }
            Console.WriteLine("Publishing complete");
            // Wait for all messages to be sent to server
            await Task.WhenAll(activePubs.Locked(() => activePubs.ToArray())).ConfigureAwait(false);

            Console.WriteLine("Publishing completed sending to server");

            // Wait for subscriber to finish shutdown
            await subTask.ConfigureAwait(false);

            watchdogCts.Cancel();
            Console.WriteLine("Subscriber finished shutdown");
            Console.WriteLine($"Sent: {sentCount}; Recv: {recvCount}");

            if (cancelAfterRecvCount is int cancelAfter)
            {
                Assert.True(recvCount >= cancelAfter && recvCount <= cancelAfter + maxMessagesInFlight, $"Incorrect recvCount: {recvCount}");
            }
            else
            {
                // Check that all messages are correctly received.
                Assert.Equal(messageCount + initialNackCount, recvCount);
                // This isn't foolproof (we can get to the right sum with wrong values) but it's a pretty strong indicator.
                Assert.Equal(sentSum, recvSum);
            }
            Console.WriteLine("Test complete.");
        }