예제 #1
0
        public static async Task Main(string[] args)
        {
            // Configuration section
            const int NumberOfProducers           = 200;
            const int NumberOfConsumers           = 10;
            const ProducerAppendBehavior Behavior = ProducerAppendBehavior.Batched;
            const bool UseSnapshotIsolation       = true;

            var container = new SqlServerContainer();

            try
            {
                Console.WriteLine("Creating sql server container ...");
                await container.InitializeAsync().ConfigureAwait(false);

                Console.WriteLine("Created.");
                var db = await container.CreateDatabaseAsync(UseSnapshotIsolation).ConfigureAwait(false);

                Console.WriteLine("ConnectionString={0}", db.ConnectionString);
                using (var store = new MsSqlStreamStoreV3(new MsSqlStreamStoreV3Settings(db.ConnectionString)
                {
                    Schema = "dbo"
                }))
                {
                    Console.WriteLine("Creating sql stream store schema ...");
                    await store.CreateSchemaIfNotExists().ConfigureAwait(false);

                    Console.WriteLine("Created.");
                    using (var scheduler = new Scheduler(SystemClock.Instance))
                    {
                        var producers = Enumerable
                                        .Range(1, NumberOfProducers)
                                        .Select(id => new Producer(id, Behavior, store, scheduler))
                                        .ToArray();

                        var consumers = Enumerable
                                        .Range(1, NumberOfConsumers)
                                        .Select(id => new Consumer(id, store, scheduler))
                                        .ToArray();

                        Console.WriteLine("Starting {0} producers ...", NumberOfProducers);
                        Array.ForEach(producers, producer => producer.Start());
                        Console.WriteLine("Started.");

                        Console.WriteLine("Starting {0} consumers ...", NumberOfConsumers);
                        Array.ForEach(consumers, consumer => consumer.Start());
                        Console.WriteLine("Started.");

                        Console.WriteLine("Press enter to exit");
                        Console.ReadLine();

                        Console.WriteLine("Stopping {0} producers ...", NumberOfProducers);
                        Array.ForEach(producers, producer => producer.Stop());
                        Console.WriteLine("Stopped.");

                        Console.WriteLine("Stopping {0} consumers ...", NumberOfConsumers);
                        Array.ForEach(consumers, consumer => consumer.Stop());
                        Console.WriteLine("Stopped.");
                    }
                }
            }
            finally
            {
                Console.WriteLine("Removing sql server container ...");
                await container.DisposeAsync().ConfigureAwait(false);

                Console.WriteLine("Removed.");
            }
        }
예제 #2
0
        public Producer(int id, ProducerAppendBehavior behavior, IStreamStore store, IScheduler scheduler)
        {
            Id        = id;
            Behavior  = behavior;
            Store     = store ?? throw new ArgumentNullException(nameof(store));
            Scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler));
            MessagePumpCancellation = new CancellationTokenSource();
            Mailbox = new BufferBlock <object>(new DataflowBlockOptions
            {
                BoundedCapacity    = int.MaxValue,
                MaxMessagesPerTask = 1,
                CancellationToken  = MessagePumpCancellation.Token
            });
            MessagePump = Task.Run(async() =>
            {
                try
                {
                    var text   = new Lorem();
                    var random = new Random();
                    while (!MessagePumpCancellation.Token.IsCancellationRequested)
                    {
                        var message = await Mailbox.ReceiveAsync(MessagePumpCancellation.Token).ConfigureAwait(false);
                        switch (message)
                        {
                        case AppendToStream append:
                            var messages = Enumerable
                                           .Range(0, random.Next(1, 100))                                                                            // produce between 1 and 99 messages per append
                                           .Select(index => new NewStreamMessage(Guid.NewGuid(), append.Stream, text.Sentences(random.Next(5, 10)))) //randomize the data a bit
                                           .ToArray();
                            if (behavior == ProducerAppendBehavior.Batched)
                            {
                                try
                                {
                                    var result = await Store
                                                 .AppendToStream(
                                        append.Stream, append.ExpectedVersion,
                                        messages,
                                        MessagePumpCancellation.Token)
                                                 .ConfigureAwait(false);

                                    await scheduler
                                    .ScheduleTellOnceAsync(
                                        () => Mailbox.Post(new AppendToStream {
                                        Stream = append.Stream, ExpectedVersion = result.CurrentVersion
                                    }),
                                        TimeSpan.FromMilliseconds(random.Next(100, 5000)),         // produce another append on the same stream in about 100 to 5000ms
                                        MessagePumpCancellation.Token)
                                    .ConfigureAwait(false);
                                }
                                catch (Exception exception)
                                {
                                    if (!MessagePumpCancellation.IsCancellationRequested)
                                    {
                                        Console.WriteLine("[{0}]AppendToStream failed because {1}", Id, exception);
                                        await scheduler
                                        .ScheduleTellOnceAsync(
                                            () => Mailbox.Post(new AppendToStream {
                                            Stream = append.Stream, ExpectedVersion = append.ExpectedVersion
                                        }),
                                            TimeSpan.FromMilliseconds(random.Next(100, 5000)),         // produce another append on the same stream in about 100 to 5000ms
                                            MessagePumpCancellation.Token)
                                        .ConfigureAwait(false);
                                    }
                                }
                            }
                            else
                            {
                                AppendResult result = new AppendResult(append.ExpectedVersion, -1);
                                try
                                {
                                    foreach (var msg in messages)
                                    {
                                        result = await Store
                                                 .AppendToStream(
                                            append.Stream, append.ExpectedVersion,
                                            messages,
                                            MessagePumpCancellation.Token)
                                                 .ConfigureAwait(false);
                                    }

                                    await scheduler
                                    .ScheduleTellOnceAsync(
                                        () => Mailbox.Post(new AppendToStream {
                                        Stream = append.Stream, ExpectedVersion = result.CurrentVersion
                                    }),
                                        TimeSpan.FromMilliseconds(random.Next(100, 5000)),         // produce another append on the same stream in about 100 to 5000ms
                                        MessagePumpCancellation.Token)
                                    .ConfigureAwait(false);
                                }
                                catch (Exception exception)
                                {
                                    if (!MessagePumpCancellation.IsCancellationRequested)
                                    {
                                        Console.WriteLine("[{0}]AppendToStream failed because {1}", Id, exception);
                                        await scheduler
                                        .ScheduleTellOnceAsync(
                                            () => Mailbox.Post(new AppendToStream {
                                            Stream = append.Stream, ExpectedVersion = result.CurrentVersion
                                        }),
                                            TimeSpan.FromMilliseconds(random.Next(100, 5000)),         // produce another append on the same stream in about 100 to 5000ms
                                            MessagePumpCancellation.Token)
                                        .ConfigureAwait(false);
                                    }
                                }
                            }
                            break;
                        }
                    }
                }
                catch (OperationCanceledException) { }
            }, MessagePumpCancellation.Token);
        }