├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── Ray 功能关系图.xml
├── Ray.xmind
├── Ray2.sln
├── example
├── Ray2.Client
│ ├── Program.cs
│ └── Ray2.Client.csproj
├── Ray2.Grain
│ ├── Account.cs
│ ├── AccountFlow.cs
│ ├── Events
│ │ ├── AccountAddBalanceEvent.cs
│ │ └── AccountTransferEvent.cs
│ ├── IAccount.cs
│ ├── IAccountFlow.cs
│ ├── IAccountStorage.cs
│ ├── IEventHandler.cs
│ ├── Ray2.Grain.csproj
│ └── States
│ │ └── AccountState.cs
└── Ray2.Host
│ ├── Program.cs
│ └── Ray2.Host.csproj
├── src
├── Ray2.PostgreSQL
│ ├── Configuration
│ │ ├── PostgreSqlRayBuilderExpansions.cs
│ │ └── PostgresqlOptions.cs
│ ├── EventStorage.cs
│ ├── IPostgreSqlEventStorage.cs
│ ├── IPostgreSqlStateStorage.cs
│ ├── IPostgreSqlTableStorage.cs
│ ├── PostgreSqlDbContext.cs
│ ├── PostgreSqlEventStorage.cs
│ ├── PostgreSqlStateStorage.cs
│ ├── PostgreSqlTableStorage.cs
│ ├── Ray2.PostgreSQL.csproj
│ └── StateStorage.cs
├── Ray2.Protobuf
│ ├── PooledMemoryStream.cs
│ ├── ProtobufSerializer.cs
│ ├── Ray2.Protobuf.csproj
│ ├── RaySiloHostBuilderExtensions.cs
│ └── SerializationType.cs
├── Ray2.RabbitMQ
│ ├── Configuration
│ │ ├── RabbitConsumeOptions.cs
│ │ ├── RabbitOptions.cs
│ │ └── RabbitRayBuilderExpansions.cs
│ ├── EventPublisher.cs
│ ├── EventSubscriber.cs
│ ├── IRabbitChannel.cs
│ ├── IRabbitChannelFactory.cs
│ ├── IRabbitConnection.cs
│ ├── IRabbitConsumer.cs
│ ├── IRabbitProducer.cs
│ ├── PublishMessage.cs
│ ├── RabbitChannel.cs
│ ├── RabbitChannelFactory.cs
│ ├── RabbitConnection.cs
│ ├── RabbitConsumer.cs
│ ├── RabbitProducer.cs
│ └── Ray2.RabbitMQ.csproj
├── Ray2.SimpleMQ
│ └── Ray2.SimpleMQ.csproj
└── Ray2
│ ├── Configuration
│ ├── Attributes
│ │ ├── EventProcessorAttribute.cs
│ │ ├── EventPublishAttribute.cs
│ │ ├── EventSourcingAttribute.cs
│ │ └── EventSubscribeAttribute.cs
│ ├── Builder
│ │ ├── EventProcessOptionsBuilder.cs
│ │ ├── EventSourceOptionsBuilder.cs
│ │ └── InternalConfigurationBuilder.cs
│ ├── Creator
│ │ ├── EventProcessOptionsCreator.cs
│ │ ├── EventPublishOptionsCreator.cs
│ │ ├── EventSourceOptionsCreator.cs
│ │ ├── EventSubscribeOptionsCreator.cs
│ │ ├── IEventProcessOptionsCreator.cs
│ │ ├── IEventPublishOptionsCreator.cs
│ │ ├── IEventSourceOptionsCreator.cs
│ │ ├── IEventSubscribeOptionsCreator.cs
│ │ ├── IInternalConfigurationCreator.cs
│ │ └── InternalConfigurationCreator.cs
│ ├── DependencyInjection
│ │ ├── IRayBuilder.cs
│ │ ├── RayBuilder.cs
│ │ └── RaySiloHostBuilderExtensions.cs
│ ├── EventInfo.cs
│ ├── EventProcessOptions.cs
│ ├── EventPublishOptions.cs
│ ├── EventSourceOptions.cs
│ ├── EventSubscribeOptions.cs
│ ├── IInternalConfiguration.cs
│ ├── InternalConfiguration.cs
│ ├── SnapshotOptions.cs
│ ├── StatusOptions.cs
│ ├── StorageOptions.cs
│ └── Validator
│ │ ├── EventProcessOptionsFluentVaildator.cs
│ │ ├── EventPublishOptionsFluentVaildator.cs
│ │ ├── EventSourceOptionsFluentVaildator.cs
│ │ ├── EventSubscribeOptionsFluentVaildator.cs
│ │ ├── IInternalConfigurationValidator.cs
│ │ ├── InternalConfigurationFluentVaildator.cs
│ │ └── RayConfigurationException.cs
│ ├── Event.cs
│ ├── EventProcess
│ ├── EventProcessCore.cs
│ ├── EventProcessExtensions.cs
│ ├── EventProcessState.cs
│ ├── EventProcessorFactory.cs
│ ├── EventProcessorGrainDispatch.cs
│ ├── IEventProcessCore.cs
│ ├── IEventProcessor.cs
│ └── IEventProcessorFactory.cs
│ ├── EventSource
│ ├── EventModel.cs
│ ├── EventSourceExtensions.cs
│ ├── EventSourcing.cs
│ ├── EventTransaction.cs
│ ├── EventTransactionModel.cs
│ ├── IEventSourcing.cs
│ └── IEventTransaction.cs
│ ├── IEvent.cs
│ ├── IRay.cs
│ ├── IState.cs
│ ├── Internal
│ ├── DataflowBufferBlock.cs
│ ├── DataflowBufferBlockFactory.cs
│ ├── DataflowBufferWrap.cs
│ ├── IDataflowBufferBlock.cs
│ ├── IDataflowBufferBlockFactory.cs
│ └── IDataflowBufferWrap.cs
│ ├── MQ
│ ├── EventPublishModel.cs
│ ├── IEventPublisher.cs
│ ├── IEventSubscriber.cs
│ ├── IMQPublisher.cs
│ ├── IMQSubscriber.cs
│ ├── MQPublishType.cs
│ ├── MQPublisher.cs
│ ├── MQPublisherExtensions.cs
│ └── MQSubscriber.cs
│ ├── Ray2.csproj
│ ├── RayGrain.cs
│ ├── RayProcessor.cs
│ ├── RayProcessorGrain.cs
│ ├── Serialization
│ ├── ISerializer.cs
│ ├── JsonSerializer.cs
│ └── SerializationType.cs
│ ├── State.cs
│ └── Storage
│ ├── IEventStorage.cs
│ ├── IStateStorage.cs
│ ├── IStorage.cs
│ ├── IStorageFactory.cs
│ ├── IStorageSharding.cs
│ ├── Model
│ ├── EventCollectionStorageModel.cs
│ ├── EventQueryModel.cs
│ ├── EventStorageInfo.cs
│ └── EventStorageModel.cs
│ ├── StorageFactory.cs
│ ├── StorageTableNameBuild.cs
│ └── StorageType.cs
├── test
├── Ray2.Integrated.Test
│ └── Ray2.Integrated.Test.csproj
├── Ray2.PostgreSQL.Test
│ ├── EventStorageTests.cs
│ ├── FakeConfig.cs
│ ├── Model
│ │ ├── TestEvent.cs
│ │ └── TestState.cs
│ ├── PostgreSqlEventStorageTests.cs
│ ├── PostgreSqlStateStorageTests.cs
│ ├── PostgreSqlTableStorageTests.cs
│ ├── Ray2.PostgreSQL.Test.csproj
│ └── StateStorageTests.cs
├── Ray2.RabbitMQ.Test
│ ├── EventPublisherTests.cs
│ ├── EventSubscriberTests.cs
│ ├── FakeConfig.cs
│ ├── Model
│ │ └── TestEvent.cs
│ ├── RabbitChannelFactoryTests.cs
│ ├── RabbitChannelTests.cs
│ ├── RabbitConnectionTests.cs
│ ├── RabbitConsumerTests.cs
│ ├── RabbitProducerTests.cs
│ └── Ray2.RabbitMQ.Test.csproj
└── Ray2.Test
│ ├── EventSource
│ └── EventSourcingTests.cs
│ ├── Internal
│ ├── DataflowBufferBlockFactoryTests.cs
│ └── DataflowBufferBlockTests.cs
│ ├── MQ
│ ├── MQPublisherTests.cs
│ └── MQSubscriberTests.cs
│ ├── Model
│ ├── TestEvent.cs
│ └── TestState.cs
│ ├── Ray2.Test.csproj
│ ├── Serialization
│ └── JsonSerializerTests.cs
│ └── Storage
│ └── StorageFactoryTests.cs
└── 未命名表单.drawio
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 阿凌
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ray2
2 |
--------------------------------------------------------------------------------
/Ray 功能关系图.xml:
--------------------------------------------------------------------------------
1 | 7V1bc6M4Fv41VO0+xIXETTyC48zUdqc66ezOTO/LFLGJzQYbN+DE7l+/Enck2WBbgJNyHrpBCGzrfOc7Fx0JSRkvt7+FznpxH8xcX4LybCsptxKEQIU6/o+07NIWBOW0YR56s6xT2fDk/XKzxrzbxpu5Ua1jHAR+7K3rjdNgtXKnca3NCcPgvd7tJfDrn7p25i7T8DR1fLb1T28WL9JWRZHl8sLvrjdfZB+t6ii7ZenkvbOu0cKZBe+VJmUiKeMwCOL0aLkduz4ZvXxg0vvu9lwtvlnoruI2N1jf5Yef/1qOX+2H9Z9/GAt/8Z/wRkuf8ub4m+wXZ1823uVD4M7wiGSnQRgvgnmwcvxJ2WqHwWY1c8nHyPis7PM1CNa4EeDG/7lxvMvE62ziADct4qWfXX0JVnF2Eej4HP+icPdX9rzk5Ac5GWn56e22evF2l52xQ5KNUhRswql7YBxybDnh3I0P9MuGh4xJ5QOyAf/NDZYu/j64Q+j6Tuy91VHkZGCcF/1KceGDTGJHSE9VT5DWdBO+JcICIkTnbr34r1I4+OxHLhp8XMqJnOyqQktvglpNwg3ypXFyurxhS3kDQ7TAk1utMHR2lQ7rwFvFUeXJD6QBd8iItOCbjEYNROk61V8ztUP98UH6DUroFT/lDDQaLJlMNMlSJaRKE0MyZQnp0sSU8JexbWmCJHsimUCaqJJ9K9l3SR9VshAD6tjdxnXYhW7k/XKekw4EGdkA4t6aLWm3uMXxvfkKN0wxNtwQN7y5YexhZreyC0tvNksUwneeXd92pq/zRBvGgR+EyecqL8kfBTzIBd5B/SQf7W5r0MgMVvYTaiahhqvsrht5JKsyrAk1J63joFdiJe8SvLxEWAloMhKACMAA4ruzY6QbxWHwWphXWBc0tppr0m+5nRMPY/TiB+/ThRPGowgrb/w36fO+8GL3ae0kGv+Ou9UlBtX8PPtMjukEewS1VyCA0kikZefvpZtQ9FlUPARd7sgYmBdpyrunaOEM3VYKv+5vvo2Vx3f5xyN6Hdv/HZsRuNGPk8IqWAkZ9opJPcqiChUPd0C6MaCNFtJUUf0R6RfN7hJPdbBZ7rkB+krszUMQebEXEEP0HMRxsORYqJgIv0aGDFPm9LgOg6kbRXvIsIRX8pQURPIIEGJ0wmmGKp1DmwKYEmqXxpQKx0+BxBOxZBzGeisx/gfW0WykQcUd8d2XeK+oIyw2bzX/d6L0N+oxdHqEPAxKHgYrD4MjDtiVOFpQZqeq44SO77t+gB0M8qi1G3r4hxGfsX7tobzQQstKvUo8xkLpoNKNWNWLc0h44UCqZqnPb0nITg5sycZxgU5aTJmR/adSPhU0Kx/qU/nAkQ5LXxmgIq2QJxkqGaD9iQV8UtHSc3NC8lAeaEOOQHiYJjdjIGfL6Sb0d3aIo2UyJFwerGpqjRI70CdNpfQJsvoEOfoEOlMoaBzUH/EO/3Ep0uSM1hFxQVueL2tOpKqileY8lxBxjJUhISszTZiTEUiyWbeSicgBgp8pU5WjVkimSlWgWdPK3OM+M8aDyqie1synL7rPZKkcfPSi5tz0en6lMb1+ana9JxIA6KJIAHA8Vqj7ceoc4rBQn5Njlhj+QQjBvpOs9BpmCeOf+Z34m9RuplFzlAUt5hDJyTRYetNMdnuYIYNhGvxU6EJO/rhh0Yvn+5Wed8lfho47Z+n5BC5/uOHMWTkcviHnvA9iSK6Mj7SDbtoRvgAd2IKWEVBnvgA6kjX6mLCjBdZ/5jDX+mYfAXTiWDN2xaAzVHRI3HHuEPBgwuOdPUGzdVeJnq+sMzDrtM27dBeBmL26JkcF6JcZtRSlRR8tauGl2FiS+LxRSz7nKSJqgZoKhEYt3UclBVuV8p+8ucmHP8VB6F5pvz/aN4emfY2XwkiKbUwrKba5k5Bx/5gdmkkBjgUkNE6CFzMpwNElExKy6MN+7HdEj7QNJ9ihVqbi0HR2o6XQtH58Vx3WcQhkpV/nNTeJFdgR7iF1tUwO+bRCn5mDadyJCOgaKn1EZZVNOqvMiSR5U6SAHntxPt1lTtPsHesBPCm+fgBZp2RpUEnDVOU70w+FM7lyio92Nd2iTDeQTQoSsjaw7VZYR+6k6YcrSLoDid4jSLiuh9KLWzZ4WN/KN+NrERzM+JwlWNaDSlzyW+KMY+XHTrqlfIQonpXcIRwLCdp1AJSamuaFmGe6DZpRfyqAo97mGnMYH8bDlfr7Cu1NiIZ2D3gVq5gGULKgJgnjLVRp0ZLJgCtGenQPTE7hUc8gabGWs4sqrpkXYs5O63Hf3SgWNMCQrmcFrP/Vb2WX0iIGv9AyOTYKHnw0VXa90v3u6aefz2A+h9fJy+5pDCoULtTC0Rkukc1mTB6CKJ6H7tPj1ys8BoWHrAwPDzZXktCG/OSG+KddATIoQBAYHiC8+Mkg0TMyR6PRFQ79wcHkuBn9gkFnjQkDgK5nN88rThlsJhHoRv0Z4mYSuXkhXg5cJwlwHNWSSWuVzFIPlwI12uZARwDV06B6Mb19TB505kSLgnbOh0/zKiYoGmfnsXiLcLbLZaELd+vMydNqC0Kz1kJWUKJXUJcLPY06DYha8URlp4BsGO04trOFnhobGOdlSPYmYqT2qRZ0aogWh8mKw+zV4nGShX3ngTArkd8uZID1fWapinde7qK7EWYnbL44L6/O1bPsLScPAGrJet2hgDVQ353nZy++f7zGoENCAw6eitc5meI8AiUVmIZkK8kWaAb517y74mVQvGjKwHgxLiRILWKYYoX5IHUcetsiW/EhCz80RowPIncWGvN/KC82RpI1kaykyNtEZNVp15uqXMCKj0JTRBSPYF9dr8n1zAUfebGIWr+ju0oRnbdguccYuYNdx/aA4ewS7gsIk3XeAg1uJXB9x9RPHT+bmkbJyWRTxr3uiGRwEk8s19JCEb4cRlD6LzeRzQtWdNG29DwpwFbKgiQb64iSlTxZrLKcuubEnXpRQpR9rTkxVEgpgtaSsIpG8UJoYV/6WBp2Bvz1lvDXL2srEmOAWiNBlhdbWsb0ttuUy+gKxxy+7mGxVLl3D2y/Nz4tkNrmH5U5JrO2WQcYgZ5jNKS2VKy+NvHQ6QW5OlWwvSdEO3YrfgAZz7JhM37OHerhOxCjQUfeYGZV8Z3u9494WS7sHE0k20iKke8kHF+xRvuzxKI5qwiJRRVDU2sizB5+uZsPGLxwRpfMMVmtlmY2ycQ9ljpKWvC/BpnET5ezWUaLSOea9BRWmUO/r6CsCB5udyzeylhmK4IrSoZECYBDT7MhTiD4sWKQ/I1gzensy4pBECfp/FFiEEgXs8mcbbl4MYjaGY4P164NsfXfGZBWWkK6t20eFMbHBpQkRfn/9JtGgCwfds5Ng05x1m/oxjs391jX2i6lnFXF+AAbXrIrEOPKN89Sf1hXXuRGYoqSb+j4UVx5xFtf2m6T26sv1lktvbYnCTCgL8bbqYCXlCcLkrVk9zEgmeyG+FeUdIgS1CNKuHX8HId92Dp+eWRW868jPX/DyHG7mRhtdqITl2FtPXOn9/SKNaTQwSHQ6V0x9mymxfpE+Y5HB57V8XKTFnNb7eocKoh7Ltjo2yb2vZUrNczfHvHaLraggbO2ihfSiCho4I5g07bVlaHUf27Ie64TqrxJCxEs3AHo620yPPn1Q3tds7tUttvr+lPVS9Bvb+PWS+gd0b23fbKdL/KXtf+uPdjf1JtpvGjz5kN3NbPIy9hLbq9VN1Qkw2WyRv7kfi+VP46VYdI4w5S3nbulPJ1/UGgtbMuU9JN01C6uPYEmucPYYjWJePEOJjZqGs00TzVwQEWNz+pYcqyzfovF8hw44QxzpbMknLV6jtY8zjyxbAb7PUtv5cTEFebayj101woCeyZ6TU51QWeFfdyBbrFSsQsGrDqGVwY8RY/waRgQv6PsTgB9H8xc0uP/
--------------------------------------------------------------------------------
/Ray.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lfzm/Ray2/8b152bd132a626c38a8e1507892ee399176e8469/Ray.xmind
--------------------------------------------------------------------------------
/example/Ray2.Client/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using Orleans;
3 | using Orleans.Runtime;
4 | using Ray2.Grain;
5 | using System;
6 | using System.Diagnostics;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 |
10 | namespace Ray2.Client
11 | {
12 | class Program
13 | {
14 | static int Main(string[] args)
15 | {
16 | return RunMainAsync().Result;
17 | }
18 |
19 | private static async Task RunMainAsync()
20 | {
21 | try
22 | {
23 | Console.ReadLine();
24 | using (var client = await StartClientWithRetries())
25 | {
26 | while (true)
27 | {
28 | // var actor = client.GetGrain(0);
29 | // Console.WriteLine("Press Enter for times...");
30 | Console.WriteLine("start");
31 | Console.ReadLine();
32 | var length = 10000;// int.Parse(Console.ReadLine());
33 | var stopWatch = new Stopwatch();
34 | stopWatch.Start();
35 | await Task.WhenAll(Enumerable.Range(0, length).Select(x =>
36 | {
37 | return client.GetGrain(1).AddAmount(1000);
38 | }));
39 | stopWatch.Stop();
40 | Console.WriteLine($"{length }次操作完成,耗时:{stopWatch.ElapsedMilliseconds}ms");
41 | await Task.Delay(200);
42 | Console.WriteLine($"余额为{await client.GetGrain(1).GetBalance()}");
43 | }
44 | }
45 | }
46 | catch (Exception e)
47 | {
48 | Console.WriteLine(e);
49 | return 1;
50 | }
51 | }
52 |
53 | private static async Task StartClientWithRetries(int initializeAttemptsBeforeFailing = 5)
54 | {
55 | int attempt = 0;
56 | IClusterClient client;
57 | while (true)
58 | {
59 | try
60 | {
61 | var builder = new ClientBuilder()
62 | .UseLocalhostClustering()
63 | .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(IAccount).Assembly).WithReferences())
64 | .ConfigureLogging(logging => logging.AddConsole());
65 | client = builder.Build();
66 | await client.Connect();
67 | Console.WriteLine("Client successfully connect to silo host");
68 | break;
69 | }
70 | catch (SiloUnavailableException)
71 | {
72 | attempt++;
73 | Console.WriteLine($"Attempt {attempt} of {initializeAttemptsBeforeFailing} failed to initialize the Orleans client.");
74 | if (attempt > initializeAttemptsBeforeFailing)
75 | {
76 | throw;
77 | }
78 | await Task.Delay(TimeSpan.FromSeconds(4));
79 | }
80 | }
81 |
82 | return client;
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/example/Ray2.Client/Ray2.Client.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.2
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/example/Ray2.Grain/Account.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.Extensions.Logging;
3 | using Orleans;
4 | using Ray2.Grain.Events;
5 | using Ray2.Grain.States;
6 |
7 | namespace Ray2.Grain
8 | {
9 | [EventSourcing("postgresql", "rabbitmq")]
10 | public class Account : RayGrain, IAccount
11 | {
12 | public Account(ILogger logger) : base(logger)
13 | {
14 |
15 | }
16 |
17 | public override async Task OnActivateAsync()
18 | {
19 | await base.OnActivateAsync();
20 | }
21 | protected override long StateId => this.GetPrimaryKeyLong();
22 |
23 | public Task AddAmount(decimal amount, string uniqueId = null)
24 | {
25 | var evt = new AccountAddBalanceEvent(amount);
26 | evt.RelationEvent = uniqueId;
27 | return this.ConcurrentWriteAsync(evt, MQ.MQPublishType.Asynchronous);
28 | }
29 |
30 | public Task GetBalance()
31 | {
32 | return Task.FromResult(State.Balance);
33 | }
34 |
35 | public Task Transfer(long toAccountId, decimal amount)
36 | {
37 | var evt = new AccountTransferEvent(toAccountId, amount, State.Balance - amount);
38 | return base.WriteAsync(evt);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/example/Ray2.Grain/AccountFlow.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using Orleans;
3 | using Ray2.Grain.Events;
4 | using Ray2.Grain.States;
5 | using System.Threading.Tasks;
6 |
7 |
8 | namespace Ray2.Grain
9 | {
10 | [EventProcessor(typeof(Account), "rabbitmq", "postgresql",OnceProcessCount =2000)]
11 | public class AccountFlow : RayProcessorGrain
12 | {
13 | private readonly ILogger logger;
14 | public AccountFlow(ILogger logger)
15 | {
16 | this.logger = logger;
17 | }
18 | protected override long StateId => this.GetPrimaryKeyLong();
19 |
20 | public override Task OnEventProcessing(IEvent @event)
21 | {
22 | switch (@event)
23 | {
24 | case AccountTransferEvent value: return TransferHandle(value);
25 | case AccountAddBalanceEvent value: return AddBalanceHandle(value);
26 | default: return Task.CompletedTask;
27 | }
28 | }
29 |
30 | private async Task TransferHandle(AccountTransferEvent evt)
31 | {
32 | var toActor = GrainFactory.GetGrain(evt.ToAccountId);
33 | await toActor.AddAmount(evt.Amount, evt.GetRelationKey());
34 | }
35 |
36 | private Task AddBalanceHandle(AccountAddBalanceEvent evt)
37 | {
38 | //this.logger.LogError($"加款:{evt.Amount}; 余额:{evt.Balance}");
39 | return Task.CompletedTask;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/example/Ray2.Grain/Events/AccountAddBalanceEvent.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.Serialization;
2 |
3 | namespace Ray2.Grain.Events
4 | {
5 | public class AccountAddBalanceEvent : Event
6 | {
7 | public AccountAddBalanceEvent() { }
8 | public AccountAddBalanceEvent(decimal amount)
9 | {
10 | Amount = amount;
11 | }
12 | public decimal Amount { get; set; }
13 | public decimal Balance { get; set; }
14 |
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/example/Ray2.Grain/Events/AccountTransferEvent.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.Serialization;
2 |
3 | namespace Ray2.Grain.Events
4 | {
5 | public class AccountTransferEvent : Event
6 | {
7 | public AccountTransferEvent() { }
8 | public AccountTransferEvent(long toAccountId, decimal amount, decimal balance)
9 | {
10 | ToAccountId = toAccountId;
11 | Amount = amount;
12 | Balance = balance;
13 | }
14 | public long ToAccountId { get; set; }
15 | public decimal Amount { get; set; }
16 | public decimal Balance { get; set; }
17 |
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/example/Ray2.Grain/IAccount.cs:
--------------------------------------------------------------------------------
1 | using Orleans;
2 | using Orleans.Concurrency;
3 | using System.Threading.Tasks;
4 |
5 | namespace Ray2.Grain
6 | {
7 | public interface IAccount:IGrainWithIntegerKey
8 | {
9 | ///
10 | /// 获取账户余额
11 | ///
12 | ///
13 | [AlwaysInterleave]
14 | Task GetBalance();
15 | ///
16 | /// 增加账户金额
17 | ///
18 | /// 金额
19 | /// 操作辨识ID(防止多次执行)
20 | ///
21 | [AlwaysInterleave]
22 | Task AddAmount(decimal amount, string uniqueId = null);
23 | ///
24 | /// 转账
25 | ///
26 | /// 目标账户ID
27 | /// 转账金额
28 | ///
29 | Task Transfer(long toAccountId, decimal amount);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/example/Ray2.Grain/IAccountFlow.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ray2.Grain
6 | {
7 | interface IAccountFlow
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/example/Ray2.Grain/IAccountStorage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ray2.Grain
6 | {
7 | interface IAccountStorage
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/example/Ray2.Grain/IEventHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ray2.Grain
6 | {
7 | interface IEventHandler
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/example/Ray2.Grain/Ray2.Grain.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
9 | all
10 | runtime; build; native; contentfiles; analyzers
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/example/Ray2.Grain/States/AccountState.cs:
--------------------------------------------------------------------------------
1 | using Ray2.Grain.Events;
2 | using System.Runtime.Serialization;
3 |
4 | namespace Ray2.Grain.States
5 | {
6 | public class AccountState : State
7 | {
8 | protected override void PlayEvent(IEvent @event)
9 | {
10 | switch (@event)
11 | {
12 | case AccountTransferEvent e:BalanceChangeHandle(e.Balance);break;
13 | case AccountAddBalanceEvent e: AmountAddEventHandle(e); break;
14 | default:
15 | break;
16 | }
17 | }
18 |
19 | private void BalanceChangeHandle(decimal balance)
20 | {
21 | this.Balance = balance;
22 | }
23 |
24 | private void AmountAddEventHandle(AccountAddBalanceEvent evt)
25 | {
26 | this.Balance += evt.Amount;
27 | evt.Balance = this.Balance;
28 | }
29 |
30 | public decimal Balance { get; set; }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/example/Ray2.Host/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using Orleans.Configuration;
3 | using Orleans.Hosting;
4 | using System;
5 | using System.Net;
6 | using System.Threading.Tasks;
7 | using Microsoft.Extensions.DependencyInjection;
8 | using Ray2.Grain;
9 | using Orleans;
10 |
11 | namespace Ray2.Host
12 | {
13 | class Program
14 | {
15 | public static int Main(string[] args)
16 | {
17 | return RunMainAsync().Result;
18 | }
19 |
20 | private static async Task RunMainAsync()
21 | {
22 | try
23 | {
24 | var host = await StartSilo();
25 | Console.WriteLine("Press Enter to terminate...");
26 | Console.ReadLine();
27 |
28 | await host.StopAsync();
29 |
30 | return 0;
31 | }
32 | catch (Exception ex)
33 | {
34 | Console.WriteLine(ex);
35 | return 1;
36 | }
37 | }
38 |
39 | private static async Task StartSilo()
40 | {
41 | // define the cluster configuration
42 | var builder = new SiloHostBuilder()
43 | .UseLocalhostClustering()
44 | .UseRay(build =>
45 | {
46 | build.AddRabbitMQ("rabbitmq", opt =>
47 | {
48 | opt.HostName = "192.168.1.250";
49 | opt.UserName = "admin";
50 | opt.Password = "admin";
51 | });
52 | build.AddPostgreSQL("postgresql", opt =>
53 | {
54 | opt.ConnectionString = "Server=localhost;Port=5432;Database=ray2;User Id=postgres; Password=sapass;Pooling=true;MaxPoolSize=50;Timeout=10;";
55 | });
56 | })
57 | .Configure(options =>
58 | {
59 | options.ClusterId = "dev";
60 | options.ServiceId = "HelloWorldApp";
61 | })
62 | .Configure(options => options.AdvertisedIPAddress = IPAddress.Loopback)
63 | .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(Account).Assembly).WithReferences())
64 | .ConfigureLogging(logging => logging.AddConsole());
65 |
66 |
67 | var host = builder.Build();
68 | await host.StartAsync();
69 | return host;
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/example/Ray2.Host/Ray2.Host.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.2
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/Ray2.PostgreSQL/Configuration/PostgreSqlRayBuilderExpansions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using Orleans.Runtime;
4 | using Ray2;
5 | using Ray2.PostgreSQL;
6 | using Ray2.Storage;
7 | using System;
8 |
9 | namespace Orleans.Hosting
10 | {
11 | public static class PostgreSqlRayBuilderExpansions
12 | {
13 | ///
14 | /// Add PostgreSql Ray storage
15 | ///
16 | ///
17 | /// Provider name
18 | /// PostgreSql configuration
19 | ///
20 | public static IRayBuilder AddPostgreSQL(this IRayBuilder build, string name, IConfiguration configuration)
21 | {
22 | build.Services.Configure(name, configuration);
23 | return build.AddPostgreSQL(name);
24 | }
25 | ///
26 | /// Add PostgreSql Ray storage
27 | ///
28 | ///
29 | /// Provider name
30 | /// PostgreSql configuration
31 | ///
32 | public static IRayBuilder AddPostgreSQL(this IRayBuilder build, string name, Action configuration)
33 | {
34 | build.Services.Configure(name, configuration);
35 | return build.AddPostgreSQL(name);
36 | }
37 |
38 | ///
39 | /// Add PostgreSql Ray storage
40 | ///
41 | ///
42 | /// Provider name
43 | ///
44 | private static IRayBuilder AddPostgreSQL(this IRayBuilder build, string name)
45 | {
46 | build.Services.AddSingletonNamedService(name, (sp, n) =>
47 | {
48 | return new StateStorage(sp, n);
49 | });
50 | build.Services.AddSingletonNamedService(name, (sp, n) =>
51 | {
52 | return new EventStorage(sp, n);
53 | });
54 | build.Services.AddSingletonNamedService(name, (sp, n) =>
55 | {
56 | return new PostgreSqlTableStorage(sp, n);
57 | });
58 | return build;
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Ray2.PostgreSQL/Configuration/PostgresqlOptions.cs:
--------------------------------------------------------------------------------
1 | using Ray2.Serialization;
2 |
3 | namespace Ray2.PostgreSQL
4 | {
5 | public class PostgreSqlOptions
6 | {
7 | public string ConnectionString { get; set; }
8 |
9 | public string SerializationType { get; set; } = Ray2.SerializationType.JsonUTF8;
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/Ray2.PostgreSQL/EventStorage.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Microsoft.Extensions.Options;
3 | using Orleans.Runtime;
4 | using Ray2.EventSource;
5 | using Ray2.Internal;
6 | using Ray2.Storage;
7 | using System;
8 | using System.Collections.Concurrent;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Threading.Tasks;
12 |
13 | namespace Ray2.PostgreSQL
14 | {
15 | public class EventStorage : IEventStorage
16 | {
17 | private readonly ConcurrentDictionary storageList = new ConcurrentDictionary();
18 | private readonly IServiceProvider _serviceProvider;
19 | private readonly IPostgreSqlTableStorage _tableStorage;
20 | private readonly PostgreSqlOptions _options;
21 | private readonly string _providerName;
22 | public EventStorage(IServiceProvider serviceProvider, string name)
23 | {
24 | this._providerName = name;
25 | this._serviceProvider = serviceProvider;
26 | this._tableStorage = serviceProvider.GetRequiredServiceByName(name);
27 | this._options = serviceProvider.GetRequiredService>().Get(name);
28 | }
29 |
30 | public Task GetAsync(string tableName, object stateId, long version)
31 | {
32 | var stotage = this.GetStorage(tableName, stateId);
33 | return stotage.GetAsync(stateId, version);
34 | }
35 |
36 | public Task> GetListAsync(string tableName, EventQueryModel queryModel)
37 | {
38 | var stotage = this.GetStorage(tableName, queryModel.StateId);
39 | return stotage.GetListAsync(queryModel);
40 | }
41 |
42 | public Task SaveAsync(List> wrapList)
43 | {
44 | Dictionary>> eventsList = wrapList.GroupBy(f => f.Data.StorageTableName).ToDictionary(x => x.Key, v => v.ToList());
45 | foreach (var key in eventsList.Keys)
46 | {
47 | var events = eventsList[key];
48 | var stotage = this.GetStorage(key, events.First().Data.StateId);
49 | stotage.SaveAsync(events);
50 | }
51 | return Task.CompletedTask;
52 | }
53 |
54 | public Task SaveAsync(EventCollectionStorageModel events)
55 | {
56 | var stotage = this.GetStorage(events.StorageTableName, events.GetStateId());
57 | return stotage.SaveAsync(events);
58 | }
59 |
60 | private IPostgreSqlEventStorage GetStorage(string tableName, object stateId)
61 | {
62 | return storageList.GetOrAdd(tableName, (key) =>
63 | {
64 | this._tableStorage.CreateEventTable(tableName, stateId);
65 | return new PostgreSqlEventStorage(this._serviceProvider, _options, this._providerName, key);
66 | });
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/Ray2.PostgreSQL/IPostgreSqlEventStorage.cs:
--------------------------------------------------------------------------------
1 | using Ray2.EventSource;
2 | using Ray2.Internal;
3 | using Ray2.Storage;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Ray2.PostgreSQL
10 | {
11 | public interface IPostgreSqlEventStorage
12 | {
13 | Task> GetListAsync( EventQueryModel queryModel);
14 | Task GetAsync(object stateId, long version);
15 | Task SaveAsync(List> wrapList);
16 | Task SaveAsync(EventCollectionStorageModel eventList);
17 |
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Ray2.PostgreSQL/IPostgreSqlStateStorage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading.Tasks;
5 |
6 | namespace Ray2.PostgreSQL
7 | {
8 | public interface IPostgreSqlStateStorage
9 | {
10 | Task DeleteAsync(object stateId);
11 | Task InsertAsync(object stateId, TState state) where TState : IState, new();
12 | Task ReadAsync(object stateId) where TState : IState, new();
13 | Task UpdateAsync(object stateId, TState state) where TState : IState, new();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Ray2.PostgreSQL/IPostgreSqlTableStorage.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace Ray2.PostgreSQL
4 | {
5 | public interface IPostgreSqlTableStorage
6 | {
7 | void CreateEventTable(string name,object stateId);
8 | void CreateStateTable(string name, object stateId);
9 |
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Ray2.PostgreSQL/PostgreSqlDbContext.cs:
--------------------------------------------------------------------------------
1 | using Dapper;
2 | using Npgsql;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Data;
6 | using System.Threading.Tasks;
7 |
8 | namespace Ray2.PostgreSQL
9 | {
10 | public class PostgreSqlDbContext : IDisposable
11 | {
12 | private readonly NpgsqlConnection dbConnection;
13 | private readonly PostgreSqlOptions options;
14 | public PostgreSqlDbContext(PostgreSqlOptions options)
15 | {
16 | this.options = options;
17 | dbConnection = new NpgsqlConnection();
18 | dbConnection.ConnectionString = this.options.ConnectionString;
19 | }
20 | public IDbTransaction BeginTransaction()
21 | {
22 | return this.dbConnection.BeginTransaction();
23 | }
24 | public IDbTransaction BeginTransaction(IsolationLevel il)
25 | {
26 | return this.dbConnection.BeginTransaction(il);
27 | }
28 | public NpgsqlBinaryExporter BeginBinaryExport(string copyToCommand)
29 | {
30 | return this.dbConnection.BeginBinaryExport(copyToCommand);
31 | }
32 | public NpgsqlBinaryImporter BeginBinaryImport(string copyFromCommand)
33 | {
34 | return this.dbConnection.BeginBinaryImport(copyFromCommand);
35 | }
36 | public void Dispose()
37 | {
38 | this.dbConnection.Dispose();
39 | }
40 | public Task OpenAsync()
41 | {
42 | this.dbConnection.Open();
43 | return Task.CompletedTask;
44 | }
45 | public Task ExecuteAsync(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
46 | {
47 | return this.dbConnection.ExecuteAsync(sql, param, transaction, commandTimeout, commandType);
48 | }
49 | public Task ExecuteScalarAsync(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
50 | {
51 | return this.dbConnection.ExecuteScalarAsync(sql, param, transaction, commandTimeout, commandType);
52 | }
53 | public Task> QueryAsync(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
54 | {
55 | return this.dbConnection.QueryAsync(sql, param, transaction, commandTimeout, commandType);
56 | }
57 |
58 |
59 | public static PostgreSqlDbContext Create(PostgreSqlOptions options)
60 | {
61 | return new PostgreSqlDbContext(options);
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Ray2.PostgreSQL/PostgreSqlStateStorage.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Microsoft.Extensions.Logging;
3 | using Microsoft.Extensions.Options;
4 | using Orleans.Runtime;
5 | using Ray2.Serialization;
6 | using System;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 |
10 | namespace Ray2.PostgreSQL
11 | {
12 | public class PostgreSqlStateStorage : IPostgreSqlStateStorage
13 | {
14 | private readonly IServiceProvider _serviceProvider;
15 | private readonly ILogger _logger;
16 | private readonly PostgreSqlOptions _options;
17 | private readonly string providerName;
18 | private readonly string tableName;
19 | private string insertSql;
20 | private string updateSql;
21 | private string deleteSql;
22 | private string selectSql;
23 |
24 | public PostgreSqlStateStorage(IServiceProvider serviceProvider, PostgreSqlOptions options, string name, string tableName)
25 | {
26 | this.providerName = name;
27 | this.tableName = tableName;
28 | this._serviceProvider = serviceProvider;
29 | this._options = serviceProvider.GetRequiredService>().Get(name);
30 | this._logger = serviceProvider.GetRequiredService>();
31 | this.BuildSql(tableName);
32 | }
33 |
34 | public async Task DeleteAsync( object stateId)
35 | {
36 | using (var db = PostgreSqlDbContext.Create(this._options))
37 | {
38 | return await db.ExecuteAsync(this.deleteSql, new { StateId = stateId.ToString() }) > 0;
39 | }
40 | }
41 | public async Task InsertAsync( object stateId, TState state) where TState : IState, new()
42 | {
43 | using (var db = PostgreSqlDbContext.Create(this._options))
44 | {
45 | var data = this.GetSerializer().Serialize(state);
46 | return await db.ExecuteAsync(this.insertSql, new { StateId = stateId.ToString(), Data = data, DataType = this._options.SerializationType }) > 0;
47 | }
48 | }
49 | public async Task ReadAsync( object stateId) where TState : IState, new()
50 | {
51 | using (var db = PostgreSqlDbContext.Create(this._options))
52 | {
53 | var list = await db.QueryAsync(this.selectSql, new { StateId = stateId.ToString() });
54 | if (list.Count() == 0)
55 | {
56 | return default(TState);
57 | }
58 | var data = list.FirstOrDefault();
59 | return this.GetSerializer(data.datatype).Deserialize(data.data);
60 | }
61 | }
62 | public async Task UpdateAsync( object stateId, TState state) where TState : IState, new()
63 | {
64 | using (var db = PostgreSqlDbContext.Create(this._options))
65 | {
66 | var data = this.GetSerializer().Serialize(state);
67 | return await db.ExecuteAsync(this.updateSql, new { StateId = stateId.ToString(), Data = data, DataType = this._options.SerializationType }) > 0;
68 | }
69 | }
70 | private ISerializer GetSerializer(string name)
71 | {
72 | return this._serviceProvider.GetRequiredServiceByName(name);
73 | }
74 | private ISerializer GetSerializer()
75 | {
76 | return this.GetSerializer(this._options.SerializationType);
77 | }
78 | private void BuildSql(string tableName)
79 | {
80 | this.updateSql = $"Update {tableName} set data=@Data,datatype =@DataType WHERE stateid=@StateId";
81 | this.selectSql = $"SELECT data,datatype FROM {tableName} WHERE stateid=@StateId";
82 | this.insertSql = $"INSERT INTO {tableName}(stateid,data,datatype) VALUES (@StateId,@Data,@DataType)";
83 | this.deleteSql = $"DELETE FROM {tableName} WHERE stateid=@StateId";
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/Ray2.PostgreSQL/Ray2.PostgreSQL.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/Ray2.PostgreSQL/StateStorage.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Microsoft.Extensions.Options;
3 | using Orleans.Runtime;
4 | using Ray2.Storage;
5 | using System;
6 | using System.Collections.Concurrent;
7 | using System.Threading.Tasks;
8 |
9 | namespace Ray2.PostgreSQL
10 | {
11 | public class StateStorage : IStateStorage
12 | {
13 | private readonly ConcurrentDictionary storageList = new ConcurrentDictionary();
14 | private readonly IServiceProvider _serviceProvider;
15 | private readonly IPostgreSqlTableStorage _tableStorage;
16 | private readonly PostgreSqlOptions _options;
17 | private readonly string _providerName;
18 |
19 | public StateStorage(IServiceProvider serviceProvider, string name)
20 | {
21 | this._providerName = name;
22 | this._serviceProvider = serviceProvider;
23 | this._tableStorage = serviceProvider.GetRequiredServiceByName(name);
24 | this._options = serviceProvider.GetRequiredService>().Get(name);
25 | }
26 | public Task DeleteAsync(string tableName, object stateId)
27 | {
28 | var stotage = this.GetStorage(tableName, stateId);
29 | return stotage.DeleteAsync(stateId);
30 | }
31 |
32 | public Task InsertAsync(string tableName, object stateId, TState state) where TState : IState, new()
33 | {
34 | var stotage = this.GetStorage(tableName, stateId);
35 | return stotage.InsertAsync(stateId, state);
36 | }
37 |
38 | public Task ReadAsync(string tableName, object stateId) where TState : IState, new()
39 | {
40 | var stotage = this.GetStorage(tableName, stateId);
41 | return stotage.ReadAsync(stateId);
42 | }
43 |
44 | public Task UpdateAsync(string tableName, object stateId, TState state) where TState : IState, new()
45 | {
46 | var stotage = this.GetStorage(tableName, stateId);
47 | return stotage.UpdateAsync(stateId, state);
48 | }
49 | private IPostgreSqlStateStorage GetStorage(string tableName, object stateId)
50 | {
51 | return storageList.GetOrAdd(tableName, (key) =>
52 | {
53 | this._tableStorage.CreateStateTable(tableName, stateId);
54 | return new PostgreSqlStateStorage(this._serviceProvider, _options, this._providerName, key);
55 | });
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Ray2.Protobuf/ProtobufSerializer.cs:
--------------------------------------------------------------------------------
1 | using Ray2.Serialization;
2 | using System;
3 | using System.Text;
4 |
5 | namespace Ray2.Protobuf
6 | {
7 | public class ProtobufSerializer : ISerializer
8 | {
9 | Encoding encoding = Encoding.UTF8;
10 | public T Deserialize(byte[] bytes)
11 | {
12 | using (PooledMemoryStream ms = new PooledMemoryStream(bytes))
13 | {
14 | return ProtoBuf.Serializer.Deserialize(ms);
15 | }
16 | }
17 |
18 | public object Deserialize(Type type, byte[] bytes)
19 | {
20 | using (PooledMemoryStream ms = new PooledMemoryStream(bytes))
21 | {
22 | return ProtoBuf.Serializer.Deserialize(type, ms);
23 | }
24 | }
25 |
26 | public byte[] Serialize(object instance)
27 | {
28 | using (PooledMemoryStream ms = new PooledMemoryStream())
29 | {
30 | ProtoBuf.Serializer.Serialize(ms, instance);
31 | var data = ms.ToArray();
32 | if (data.Length == 0)
33 | throw new Exception("Protobuf serialization failed, data is empty after serialization");
34 | else
35 | return data;
36 | }
37 | }
38 | public byte[] Serialize(T instance)
39 | {
40 | using (PooledMemoryStream ms = new PooledMemoryStream())
41 | {
42 | ProtoBuf.Serializer.Serialize(ms, instance);
43 | var data = ms.ToArray();
44 | if (data.Length == 0)
45 | throw new Exception("Protobuf serialization failed, data is empty after serialization");
46 | else
47 | return data;
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Ray2.Protobuf/Ray2.Protobuf.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/Ray2.Protobuf/RaySiloHostBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using Orleans.Runtime;
2 | using Ray2;
3 | using Ray2.Protobuf;
4 | using Ray2.Serialization;
5 |
6 | namespace Microsoft.Extensions.DependencyInjection
7 | {
8 | public static class RaySiloHostBuilderExtensions
9 | {
10 | ///
11 | /// Add Protobuf serialization
12 | ///
13 | ///
14 | ///
15 | public static IRayBuilder AddProtobuf(this IRayBuilder build)
16 | {
17 | build.Services.AddSingletonNamedService(Ray2.Protobuf.SerializationType.Protobuf);
18 | return build;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Ray2.Protobuf/SerializationType.cs:
--------------------------------------------------------------------------------
1 | namespace Ray2.Protobuf
2 | {
3 | public class SerializationType
4 | {
5 | ///
6 | /// Protobuf
7 | ///
8 | public const string Protobuf = "Protobuf";
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/Ray2.RabbitMQ/Configuration/RabbitConsumeOptions.cs:
--------------------------------------------------------------------------------
1 | namespace Ray2.RabbitMQ.Configuration
2 | {
3 | public class RabbitConsumeOptions
4 | {
5 | public string Group { get; set; }
6 | public string Topic { get; set; }
7 | public bool AutoAck { get; set; }
8 | public int NoticeRetriesCount { get; set; }
9 | public ushort OneFetchCount { get; set; } = 20;
10 | public int MaxConsumerCount { get; set; } = 10;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Ray2.RabbitMQ/Configuration/RabbitOptions.cs:
--------------------------------------------------------------------------------
1 | using RabbitMQ.Client;
2 | using System.Collections.Generic;
3 |
4 | namespace Ray2.RabbitMQ.Configuration
5 | {
6 | public class RabbitOptions
7 | {
8 | ///
9 | /// This is the UserName of Rebbit
10 | ///
11 | public string UserName { get; set; }
12 | ///
13 | /// This is the Password of Rebbit
14 | ///
15 | public string Password { get; set; }
16 | ///
17 | /// ///
18 | /// This is the VirtualHost of Rebbit
19 | ///
20 | ///
21 | public string VirtualHost { get; set; } = "/";
22 | ///
23 | /// Data serialization type
24 | ///
25 | public string SerializationType { get; set; } = Ray2.SerializationType.JsonUTF8;
26 | ///
27 | /// This is the HostName of Rebbit
28 | ///
29 | public string HostName { get; set; }
30 | ///
31 | /// This is the HostName of multiple Rebbits.
32 | ///
33 | public string[] HostNames { get; set; } = new string[0];
34 | ///
35 | /// This is the number of connection pools
36 | ///
37 | public int ConnectionPoolCount { get; set; } = 10;
38 | ///
39 | ///This is the Consumer Options
40 | ///
41 | public List ConsumeOptions { get; set; } = new List();
42 | public List EndPoints
43 | {
44 | get
45 | {
46 |
47 | var list = new List();
48 | foreach (var host in HostNames)
49 | {
50 | list.Add(AmqpTcpEndpoint.Parse(host));
51 | }
52 | if (!string.IsNullOrEmpty(HostName))
53 | {
54 | list.Add(AmqpTcpEndpoint.Parse(this.HostName));
55 |
56 | }
57 | return list;
58 | }
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Ray2.RabbitMQ/Configuration/RabbitRayBuilderExpansions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using Orleans.Runtime;
4 | using Ray2;
5 | using Ray2.MQ;
6 | using Ray2.RabbitMQ;
7 | using Ray2.RabbitMQ.Configuration;
8 | using System;
9 |
10 | namespace Orleans.Hosting
11 | {
12 | public static class RabbitRayBuilderExpansions
13 | {
14 | ///
15 | /// Add RabbitMQ
16 | ///
17 | ///
18 | /// Provider name
19 | /// RabbitMQ configuration
20 | ///
21 | public static IRayBuilder AddRabbitMQ(this IRayBuilder build, string name, IConfiguration configuration)
22 | {
23 | build.Services.Configure(name, configuration);
24 | return build.AddRabbitMQ(name);
25 | }
26 |
27 | ///
28 | /// Add RabbitMQ
29 | ///
30 | ///
31 | /// Provider name
32 | /// RabbitMQ configuration
33 | ///
34 | public static IRayBuilder AddRabbitMQ(this IRayBuilder build, string name, Action configuration)
35 | {
36 | build.Services.Configure(name, configuration);
37 | return build.AddRabbitMQ(name);
38 | }
39 |
40 | ///
41 | /// Add RabbitMQ
42 | ///
43 | ///
44 | /// Provider name
45 | ///
46 | private static IRayBuilder AddRabbitMQ(this IRayBuilder build, string name)
47 | {
48 | build.Services.AddSingletonNamedService(name, (sp, n) =>
49 | {
50 | return new EventPublisher(sp, n);
51 | });
52 | build.Services.AddSingletonNamedService(name, (sp, n) =>
53 | {
54 | return new EventSubscriber(sp, n);
55 | });
56 | build.Services.AddSingletonNamedService(name, (sp, n) =>
57 | {
58 | return new RabbitChannelFactory(sp, n);
59 | });
60 | return build;
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Ray2.RabbitMQ/EventPublisher.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Microsoft.Extensions.Logging;
3 | using Microsoft.Extensions.Options;
4 | using Orleans.Runtime;
5 | using Ray2.EventSource;
6 | using Ray2.MQ;
7 | using Ray2.RabbitMQ.Configuration;
8 | using Ray2.Serialization;
9 | using System;
10 | using System.Collections.Concurrent;
11 | using System.Collections.Generic;
12 | using System.Threading;
13 | using System.Threading.Tasks;
14 |
15 | namespace Ray2.RabbitMQ
16 | {
17 | public class EventPublisher : IEventPublisher
18 | {
19 | private readonly ConcurrentQueue ProducersPool = new ConcurrentQueue();
20 | private readonly IServiceProvider _serviceProvider;
21 | private readonly RabbitOptions _options;
22 | private readonly ILogger _logger;
23 | private readonly ISerializer _serializer;
24 | private readonly string providerName;
25 | private int MaxChannelCount = 0;
26 | public EventPublisher(IServiceProvider serviceProvider, string providerName)
27 | {
28 | this.providerName = providerName;
29 | this._serviceProvider = serviceProvider;
30 | this._logger = this._serviceProvider.GetRequiredService>();
31 | this._options = serviceProvider.GetRequiredService>().Get(providerName);
32 | this._serializer = this._serviceProvider.GetRequiredServiceByName(_options.SerializationType);
33 | this.MaxChannelCount = this._options.ConnectionPoolCount * 20;//20 channels per connection pool
34 | }
35 |
36 | public Task Publish(string topic, EventModel model)
37 | {
38 | IRabbitProducer producer = this.GetProducer();
39 | return this.Publish(topic, model, producer);
40 | }
41 |
42 | public async Task Publish(string topic, EventModel model, IRabbitProducer producer)
43 | {
44 | var message = new PublishMessage(model, this._serializer);
45 | bool ret = await producer.Publish(topic, topic, message);
46 | this.EnqueuePool(producer);
47 | return ret;
48 | }
49 |
50 | public IRabbitProducer GetProducer()
51 | {
52 | IRabbitProducer producer;
53 | if (ProducersPool.TryDequeue(out producer))
54 | {
55 | if (producer.IsAvailable())
56 | {
57 | return producer;
58 | }
59 | else
60 | {
61 | Interlocked.CompareExchange(ref this.MaxChannelCount, 1, 0);
62 | }
63 | }
64 | else
65 | {
66 | if (this.MaxChannelCount > 0)
67 | {
68 | Interlocked.Decrement(ref this.MaxChannelCount);
69 | producer = new RabbitProducer(this._serviceProvider, this.providerName, this._serializer);
70 | return producer;
71 | }
72 | else
73 | {
74 | Task.Delay(500).GetAwaiter().GetResult();
75 | }
76 | }
77 | return this.GetProducer();
78 | }
79 |
80 | public void EnqueuePool(IRabbitProducer producer)
81 | {
82 | ProducersPool.Enqueue(producer);
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/Ray2.RabbitMQ/IRabbitChannel.cs:
--------------------------------------------------------------------------------
1 | using RabbitMQ.Client;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace Ray2.RabbitMQ
7 | {
8 | public interface IRabbitChannel
9 | {
10 | IRabbitConnection Connection { get; }
11 | bool IsOpen();
12 | void Close();
13 | IModel Model { get; }
14 | uint MessageCount(string quene);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Ray2.RabbitMQ/IRabbitChannelFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading.Tasks;
5 |
6 | namespace Ray2.RabbitMQ
7 | {
8 | public interface IRabbitChannelFactory
9 | {
10 | IRabbitChannel GetChannel();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Ray2.RabbitMQ/IRabbitConnection.cs:
--------------------------------------------------------------------------------
1 | using RabbitMQ.Client;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace Ray2.RabbitMQ
7 | {
8 | public interface IRabbitConnection
9 | {
10 | IConnection Connection { get; }
11 | IRabbitChannel CreateChannel();
12 | void Close();
13 | bool IsOpen();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Ray2.RabbitMQ/IRabbitConsumer.cs:
--------------------------------------------------------------------------------
1 | using Ray2.EventProcess;
2 | using Ray2.RabbitMQ.Configuration;
3 | using System.Threading.Tasks;
4 |
5 | namespace Ray2.RabbitMQ
6 | {
7 | ///
8 | /// This is the consumer interface of Rebbit.
9 | ///
10 | public interface IRabbitConsumer
11 | {
12 | string Queue { get; }
13 | string Exchange { get; }
14 | RabbitConsumeOptions Options { get; }
15 | IEventProcessor Processor { get; }
16 | ///
17 | /// Subscribe to RabbitMQ
18 | ///
19 | ///
20 | Task Subscribe(string queue, string exchange, IEventProcessor processor, RabbitConsumeOptions options);
21 | ///
22 | /// Is this consumer available?
23 | ///
24 | ///
25 | bool IsAvailable();
26 | ///
27 | /// Need to expand
28 | ///
29 | ///
30 | bool IsExpand();
31 | ///
32 | /// Stop listening
33 | ///
34 | ///
35 | Task Close();
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Ray2.RabbitMQ/IRabbitProducer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading.Tasks;
5 |
6 | namespace Ray2.RabbitMQ
7 | {
8 | ///
9 | /// This is the producer interface of Rebbit.
10 | ///
11 | public interface IRabbitProducer
12 | {
13 | ///
14 | /// Is this producer available?
15 | ///
16 | ///
17 | bool IsAvailable();
18 |
19 | void Close();
20 | Task Publish(string exchange, string routingKey, PublishMessage message);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Ray2.RabbitMQ/PublishMessage.cs:
--------------------------------------------------------------------------------
1 | //using ProtoBuf;
2 |
3 | using Ray2.EventSource;
4 | using Ray2.Serialization;
5 | using System;
6 | using System.Runtime.Serialization;
7 |
8 | namespace Ray2.RabbitMQ
9 | {
10 | [DataContract]
11 | public class PublishMessage
12 | {
13 | public PublishMessage() { }
14 | public PublishMessage(EventModel model, ISerializer serializer)
15 | {
16 | this.TypeCode = model.TypeCode;
17 | this.Version = model.Version;
18 | this.Data = serializer.Serialize(model.Event);
19 | }
20 | [DataMember(Order = 1)]
21 | public string TypeCode { get; set; }
22 | [DataMember(Order = 2)]
23 | public Int64 Version { get; set; }
24 | [DataMember(Order = 3)]
25 | public byte[] Data { get; set; }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Ray2.RabbitMQ/RabbitChannel.cs:
--------------------------------------------------------------------------------
1 | using RabbitMQ.Client;
2 |
3 | namespace Ray2.RabbitMQ
4 | {
5 | public class RabbitChannel : IRabbitChannel
6 | {
7 | public IRabbitConnection Connection { get; }
8 | public IModel Model { get; }
9 |
10 | public RabbitChannel(IRabbitConnection conn)
11 | {
12 | this.Connection = conn;
13 | this.Model = conn.Connection.CreateModel();
14 | }
15 |
16 | public void Close()
17 | {
18 | this.Model.Close();
19 | this.Model.Dispose();
20 | }
21 | public bool IsOpen()
22 | {
23 | if (!this.Model.IsClosed && this.Model.IsOpen)
24 | {
25 | return true;
26 | }
27 | else
28 | {
29 | this.Model.Dispose();
30 | return false;
31 | }
32 | }
33 | public uint MessageCount(string quene)
34 | {
35 | if (this.IsOpen())
36 | {
37 | return this.Model.MessageCount(quene);
38 | }
39 | else
40 | {
41 | return 0;
42 | }
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/src/Ray2.RabbitMQ/RabbitChannelFactory.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Microsoft.Extensions.Logging;
3 | using Microsoft.Extensions.Options;
4 | using Ray2.RabbitMQ.Configuration;
5 | using System;
6 | using System.Collections.Concurrent;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | namespace Ray2.RabbitMQ
11 | {
12 | public class RabbitChannelFactory : IRabbitChannelFactory
13 | {
14 | private int RemainderCount;//Number of remaining connection pools
15 | private readonly ConcurrentQueue ConnectionPoll = new ConcurrentQueue();
16 | private readonly RabbitOptions Options;
17 | private readonly IServiceProvider _serviceProvider;
18 | private readonly ILogger _logger;
19 | public RabbitChannelFactory(IServiceProvider serviceProvider, string providerName)
20 | {
21 | this._serviceProvider = serviceProvider;
22 | this._logger = serviceProvider.GetRequiredService>();
23 | this.Options = serviceProvider.GetRequiredService>().Get(providerName);
24 | this.RemainderCount = this.Options.ConnectionPoolCount > 0 ? this.Options.ConnectionPoolCount : 10;
25 | }
26 |
27 | public IRabbitChannel GetChannel()
28 | {
29 | IRabbitConnection connection;
30 | if (this.RemainderCount > 0)
31 | {
32 | Interlocked.Decrement(ref this.RemainderCount);
33 | connection = new RabbitConnection(this._serviceProvider, this.Options);
34 | }
35 | else
36 | {
37 | if (ConnectionPoll.TryDequeue(out IRabbitConnection conn))
38 | {
39 | connection = conn;
40 | }
41 | else
42 | {
43 | Task.Delay(1000).GetAwaiter().GetResult();
44 | return this.GetChannel();
45 | }
46 | }
47 | if (connection.IsOpen())
48 | {
49 | //Continue to line up
50 | var channel = connection.CreateChannel();
51 | ConnectionPoll.Enqueue(connection);
52 | return channel;
53 | }
54 | else
55 | {
56 | Interlocked.CompareExchange(ref this.RemainderCount, 1, 0);
57 | return this.GetChannel();
58 | }
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Ray2.RabbitMQ/RabbitConnection.cs:
--------------------------------------------------------------------------------
1 | using RabbitMQ.Client;
2 | using Ray2.RabbitMQ.Configuration;
3 | using System;
4 |
5 | namespace Ray2.RabbitMQ
6 | {
7 | public class RabbitConnection : IRabbitConnection
8 | {
9 | private readonly RabbitOptions Options;
10 | private readonly IServiceProvider _serviceProvider;
11 | private readonly ConnectionFactory _connectionFactory;
12 | public IConnection Connection { get; }
13 | public RabbitConnection(IServiceProvider serviceProvider, RabbitOptions options)
14 | {
15 | this._serviceProvider = serviceProvider;
16 | this.Options = options;
17 | this._connectionFactory = new ConnectionFactory
18 | {
19 | UserName = this.Options.UserName,
20 | Password = this.Options.Password,
21 | VirtualHost = this.Options.VirtualHost,
22 | AutomaticRecoveryEnabled = false
23 | };
24 | this.Connection = this._connectionFactory.CreateConnection(this.Options.EndPoints);
25 | }
26 |
27 | public void Close()
28 | {
29 | this.Connection.Close();
30 | this.Connection.Dispose();
31 | }
32 |
33 | public IRabbitChannel CreateChannel()
34 | {
35 | if (!this.Connection.IsOpen)
36 | {
37 | throw new Exception("rabbitMQ service has been disconnected");
38 | }
39 | return new RabbitChannel(this);
40 | }
41 |
42 | public bool IsOpen()
43 | {
44 | return this.Connection.IsOpen;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Ray2.RabbitMQ/RabbitProducer.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Microsoft.Extensions.Logging;
3 | using Orleans.Runtime;
4 | using RabbitMQ.Client;
5 | using Ray2.Serialization;
6 | using System;
7 | using System.Threading.Tasks;
8 |
9 | namespace Ray2.RabbitMQ
10 | {
11 | public class RabbitProducer : IRabbitProducer
12 | {
13 | private readonly IServiceProvider _serviceProvider;
14 | private readonly ISerializer _serializer;
15 | private readonly ILogger _logger;
16 | private readonly IRabbitChannel _channel;
17 | private readonly string providerName;
18 | public RabbitProducer(IServiceProvider serviceProvider, string providerName, ISerializer serializer)
19 | {
20 | this.providerName = providerName;
21 | this._serviceProvider = serviceProvider;
22 | this._serializer = serializer;
23 | this._logger = this._serviceProvider.GetRequiredService>();
24 | var channelFactory = serviceProvider.GetRequiredServiceByName(providerName);
25 | this._channel = channelFactory.GetChannel();
26 | }
27 |
28 | public void Close()
29 | {
30 | this._channel.Close();
31 | }
32 |
33 | public bool IsAvailable()
34 | {
35 | return this._channel.IsOpen();
36 | }
37 |
38 | public Task Publish(string exchange, string routingKey, PublishMessage message)
39 | {
40 | try
41 | {
42 | var data = this._serializer.Serialize(message);
43 | this._channel.Model.BasicPublish(exchange, routingKey, null, data);
44 | return Task.FromResult(true);
45 | }
46 | catch (Exception ex)
47 | {
48 | this._logger.LogError(ex, $"{providerName}-{exchange}&{routingKey} RabbitMQ publishing failed");
49 | return Task.FromResult(false);
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Ray2.RabbitMQ/Ray2.RabbitMQ.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/Ray2.SimpleMQ/Ray2.SimpleMQ.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Attributes/EventProcessorAttribute.cs:
--------------------------------------------------------------------------------
1 | using Ray2.Configuration;
2 | using System;
3 |
4 | namespace Ray2
5 | {
6 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
7 | public class EventProcessorAttribute : Attribute
8 | {
9 | public EventProcessorAttribute(string eventSourceName, string mqProviderName, string storageProviderName)
10 | {
11 | this.EventSourceName = eventSourceName;
12 | this.Topic = this.EventSourceName;
13 |
14 | this.MQProvider = mqProviderName;
15 | this.StorageProvider = storageProviderName;
16 | }
17 | public EventProcessorAttribute( Type eventSource, string mqProviderName, string storageProviderName):this(eventSource.Name,mqProviderName,storageProviderName)
18 | {
19 |
20 | }
21 | public string Name { get; set; }
22 | public string EventSourceName { get; set; }
23 | public string MQProvider { get; set; }
24 | public string Topic { get; set; }
25 | public string StorageProvider { get; set; }
26 | public string ShardingStrategy { get; set; }
27 | public int OnceProcessCount { get; set; } = 1;
28 | public TimeSpan OnceProcessTimeout { get; set; } = TimeSpan.FromMinutes(5);
29 | public StatusMode StatusMode { get; set; } = StatusMode.Asynchronous;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Attributes/EventPublishAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Ray2
4 | {
5 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
6 | public class EventPublishAttribute : Attribute
7 | {
8 | public EventPublishAttribute(string topic,string mqprovider)
9 | {
10 | this.Topic = topic;
11 | this.MQProvider = mqprovider;
12 | }
13 | ///
14 | /// This is a message queue provider
15 | ///
16 | public string MQProvider { get; set; }
17 | ///
18 | /// mq topic
19 | ///
20 | public string Topic { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Attributes/EventSourcingAttribute.cs:
--------------------------------------------------------------------------------
1 | using Ray2.Configuration;
2 | using System;
3 |
4 | namespace Ray2
5 | {
6 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
7 | public class EventSourcingAttribute : Attribute
8 | {
9 | public EventSourcingAttribute(string storageProviderName, string mqProviderName)
10 | {
11 | this.MQProvider = mqProviderName;
12 | this.StorageProvider = storageProviderName;
13 | }
14 | public string Name { get; set; }
15 | public string MQProvider { get; set; }
16 | public string Topic { get; set; }
17 | public string StorageProvider { get; set; }
18 | public string ShardingStrategy { get; set; }
19 | public SnapshotType SnapshotType { get; set; } = SnapshotType.Asynchronous;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Attributes/EventSubscribeAttribute.cs:
--------------------------------------------------------------------------------
1 | using Ray2.Configuration;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace Ray2
7 | {
8 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
9 | public class EventSubscribeAttribute : Attribute
10 | {
11 | public EventSubscribeAttribute(string topic, string mqprovider)
12 | {
13 | this.Topic = topic;
14 | this.MQProvider = mqprovider;
15 | }
16 | public string Topic { get; set; }
17 | public string MQProvider { get; set; }
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Builder/EventProcessOptionsBuilder.cs:
--------------------------------------------------------------------------------
1 | using Orleans;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace Ray2.Configuration.Builder
6 | {
7 | public class EventProcessOptionsBuilder
8 | {
9 | private string _processorName;
10 | private string _processorFullName;
11 | private string _eventSourceName;
12 | private int _onceProcessCount;
13 | private TimeSpan _onceProcessTimeout;
14 | private StatusOptions _statusOptions;
15 | private IList _eventSubscribeOptions;
16 | private ProcessorType _processorType;
17 | private Type _processorHandle;
18 | public EventProcessOptionsBuilder WithProcessor(string name, Type type)
19 | {
20 | this._processorHandle = type;
21 | this._processorName = name;
22 | this._processorFullName = type.FullName;
23 | if (typeof(Grain).IsAssignableFrom(type))
24 | {
25 | _processorType = ProcessorType.GrainProcessor;
26 | }
27 | else
28 | {
29 | _processorType = ProcessorType.SimpleProcessor;
30 | }
31 | return this;
32 | }
33 |
34 | public EventProcessOptionsBuilder WithEventSourceName(string name)
35 | {
36 | this._eventSourceName = name;
37 | return this;
38 | }
39 |
40 | public EventProcessOptionsBuilder WithOnceProcessConfig(int onceProcessCount, TimeSpan onceProcessTimeout)
41 | {
42 | this._onceProcessCount = onceProcessCount;
43 | this._onceProcessTimeout = onceProcessTimeout;
44 | return this;
45 | }
46 |
47 | public EventProcessOptionsBuilder WithStatusOptions(StatusOptions statusOptions)
48 | {
49 | this._statusOptions = statusOptions;
50 | return this;
51 | }
52 |
53 | public EventProcessOptionsBuilder WithEventSubscribeOptions(IList eventSubscribeOptions)
54 | {
55 | this._eventSubscribeOptions = eventSubscribeOptions;
56 | return this;
57 | }
58 |
59 | public EventProcessOptions Build()
60 | {
61 | return new EventProcessOptions(_processorName, _processorFullName, _processorType, _processorHandle, _eventSourceName, _onceProcessCount, _onceProcessTimeout, _statusOptions, _eventSubscribeOptions);
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Builder/EventSourceOptionsBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Ray2.Configuration.Builder
4 | {
5 | public class EventSourceOptionsBuilder
6 | {
7 | private string _eventSourceName;
8 | private string _fourcingFullName;
9 | private SnapshotOptions _snapshotOptions;
10 | private StorageOptions _storageOptions;
11 |
12 | public EventSourceOptionsBuilder WithEventSourcing(string name, Type type)
13 | {
14 | this._eventSourceName = name;
15 | this._fourcingFullName = type.FullName;
16 | return this;
17 | }
18 |
19 | public EventSourceOptionsBuilder WithSnapshotOptions(SnapshotOptions snapshotOptions)
20 | {
21 | this._snapshotOptions = snapshotOptions;
22 | return this;
23 | }
24 |
25 | public EventSourceOptionsBuilder WithStorageOptions(StorageOptions storageOptions)
26 | {
27 | this._storageOptions = storageOptions;
28 | return this;
29 | }
30 | public EventSourceOptions Build()
31 | {
32 | return new EventSourceOptions(_eventSourceName, _fourcingFullName, _snapshotOptions, _storageOptions);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Builder/InternalConfigurationBuilder.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Ray2.Configuration.Builder
4 | {
5 | ///
6 | /// System internal configuration builder
7 | ///
8 | public class InternalConfigurationBuilder
9 | {
10 | InternalConfiguration configuration;
11 | public InternalConfigurationBuilder()
12 | {
13 | configuration = new InternalConfiguration();
14 | }
15 |
16 | public void WithEventProcessOptions(EventProcessOptions options)
17 | {
18 | this.configuration._eventProcessOptions.Add(options.ProcessorName, options);
19 | this.configuration._eventProcessOptionsByProcessor.Add(options.ProcessorFullName, options);
20 | }
21 |
22 | public void WithEventProcessOptions(IList options)
23 | {
24 | foreach (var item in options)
25 | {
26 | this.WithEventProcessOptions(item);
27 | }
28 | }
29 | public void WithEventSourceOptions(EventSourceOptions options)
30 | {
31 | this.configuration._eventSourceOptions.Add(options.EventSourceName, options);
32 | this.configuration._eventSourceOptionsBySource.Add(options.SourcingFullName, options);
33 | }
34 | public void WithEventPublishOptions(string name, EventPublishOptions options)
35 | {
36 | this.configuration._eventPublishOptions.Add(name, options);
37 | }
38 | public void WithEventInfo(EventInfo info)
39 | {
40 | this.configuration._eventInfos.Add(info.Name, info);
41 | }
42 | public InternalConfiguration Build()
43 | {
44 | return configuration;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Creator/EventProcessOptionsCreator.cs:
--------------------------------------------------------------------------------
1 | using Ray2.Configuration.Builder;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Reflection;
5 |
6 | namespace Ray2.Configuration.Creator
7 | {
8 | public class EventProcessOptionsCreator : IEventProcessOptionsCreator
9 | {
10 | private readonly IEventSubscribeOptionsCreator _eventSubscribeOptionsCreator;
11 | public EventProcessOptionsCreator(IEventSubscribeOptionsCreator eventSubscribeOptionsCreator)
12 | {
13 | this._eventSubscribeOptionsCreator = eventSubscribeOptionsCreator;
14 | }
15 |
16 | public EventProcessOptions Create(Type type)
17 | {
18 | List options = new List();
19 | var attribute = type.GetCustomAttribute();
20 | if (attribute == null)
21 | {
22 | throw new Exception($"The {type.FullName} processor does not have an {nameof(EventProcessorAttribute)} configured.");
23 | }
24 |
25 | var statusOptions = this.CreateStatusOptions(attribute);
26 | var eventSubscribeOptionsList = this._eventSubscribeOptionsCreator.Create(type);
27 | string name = attribute.Name;
28 | if (string.IsNullOrEmpty(name))
29 | {
30 | name = type.Name;
31 | }
32 | return new EventProcessOptionsBuilder()
33 | .WithProcessor(name, type)
34 | .WithEventSourceName(attribute.EventSourceName)
35 | .WithOnceProcessConfig(attribute.OnceProcessCount, attribute.OnceProcessTimeout)
36 | .WithStatusOptions(statusOptions)
37 | .WithEventSubscribeOptions(eventSubscribeOptionsList)
38 | .Build();
39 | }
40 |
41 | private StatusOptions CreateStatusOptions(EventProcessorAttribute attribute)
42 | {
43 | return new StatusOptions(attribute.StorageProvider, attribute.ShardingStrategy, attribute.StatusMode);
44 | }
45 |
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Creator/EventPublishOptionsCreator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 |
4 | namespace Ray2.Configuration.Creator
5 | {
6 | public class EventPublishOptionsCreator : IEventPublishOptionsCreator
7 | {
8 | public EventPublishOptions Create(Type type)
9 | {
10 | var attr = type.GetCustomAttribute();
11 | if (attr != null)
12 | {
13 | string topic = attr.Topic;
14 | if (string.IsNullOrEmpty(topic))
15 | {
16 | topic = type.Name;
17 | }
18 | return new EventPublishOptions(topic, attr.MQProvider, type.FullName);
19 | }
20 |
21 | var attribute = type.GetCustomAttribute();
22 | if (attribute == null)
23 | {
24 | return null;
25 | }
26 | return new EventPublishOptions(attribute.Topic, attribute.MQProvider, type.FullName);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Creator/EventSourceOptionsCreator.cs:
--------------------------------------------------------------------------------
1 | using Ray2.Configuration.Builder;
2 | using System;
3 | using System.Reflection;
4 |
5 | namespace Ray2.Configuration.Creator
6 | {
7 | public class EventSourceOptionsCreator : IEventSourceOptionsCreator
8 | {
9 | public EventSourceOptions Create(Type type)
10 | {
11 | var attr = type.GetCustomAttribute();
12 | if (attr == null)
13 | {
14 | throw new Exception($"The {type.FullName} does not have an {nameof(EventSourcingAttribute)} configured.");
15 | }
16 |
17 | var snapshotOptions = this.CreateSnapshotOptions(attr);
18 | var storageOptions = this.CreateStorageOptions(attr);
19 | string name = attr.Name;
20 | if (string.IsNullOrEmpty(name))
21 | {
22 | name = type.Name;
23 | }
24 |
25 | return new EventSourceOptionsBuilder().WithEventSourcing(name, type)
26 | .WithSnapshotOptions(snapshotOptions)
27 | .WithStorageOptions(storageOptions)
28 | .Build();
29 | }
30 |
31 | private SnapshotOptions CreateSnapshotOptions(EventSourcingAttribute attribute)
32 | {
33 | if (attribute.SnapshotType == SnapshotType.NoSnapshot)
34 | {
35 | return new SnapshotOptions();
36 | }
37 | else
38 | {
39 | return new SnapshotOptions(attribute.StorageProvider, attribute.ShardingStrategy, attribute.SnapshotType);
40 | }
41 | }
42 | private StorageOptions CreateStorageOptions(EventSourcingAttribute attribute)
43 | {
44 | return new StorageOptions(attribute.StorageProvider, attribute.ShardingStrategy);
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Creator/EventSubscribeOptionsCreator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 |
6 | namespace Ray2.Configuration.Creator
7 | {
8 | public class EventSubscribeOptionsCreator : IEventSubscribeOptionsCreator
9 | {
10 | public IList Create(Type type)
11 | {
12 | IList optionsList = new List();
13 | var attribute = type.GetCustomAttribute();
14 | var options = this.CreateEventSubscribeOptions(type.FullName, attribute);
15 | optionsList.Add(options);
16 |
17 | var attributes = type.GetCustomAttributes();
18 | if (attributes == null || attributes.Count() == 0)
19 | return optionsList;
20 |
21 | foreach (var attr in attributes)
22 | {
23 | options = this.CreateEventSubscribeOptions(type.FullName, attr);
24 | optionsList.Add(options);
25 | }
26 | return optionsList;
27 | }
28 |
29 |
30 | private EventSubscribeOptions CreateEventSubscribeOptions(string fullName, EventSubscribeAttribute attribute)
31 | {
32 | return new EventSubscribeOptions(attribute.MQProvider, attribute.Topic, fullName);
33 | }
34 | private EventSubscribeOptions CreateEventSubscribeOptions(string fullName, EventProcessorAttribute attribute)
35 | {
36 | return new EventSubscribeOptions(attribute.MQProvider, attribute.Topic, fullName);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Creator/IEventProcessOptionsCreator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Ray2.Configuration.Creator
5 | {
6 | public interface IEventProcessOptionsCreator
7 | {
8 | EventProcessOptions Create(Type type);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Creator/IEventPublishOptionsCreator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Ray2.Configuration.Creator
4 | {
5 | public interface IEventPublishOptionsCreator
6 | {
7 | EventPublishOptions Create(Type type);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Creator/IEventSourceOptionsCreator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Ray2.Configuration.Creator
4 | {
5 | public interface IEventSourceOptionsCreator
6 | {
7 | EventSourceOptions Create(Type type);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Creator/IEventSubscribeOptionsCreator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Ray2.Configuration.Creator
5 | {
6 | public interface IEventSubscribeOptionsCreator
7 | {
8 | IList Create(Type type);
9 |
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Creator/IInternalConfigurationCreator.cs:
--------------------------------------------------------------------------------
1 | namespace Ray2.Configuration.Creator
2 | {
3 | public interface IInternalConfigurationCreator
4 | {
5 | InternalConfiguration Create();
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/DependencyInjection/IRayBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 | using Microsoft.Extensions.DependencyInjection;
3 |
4 | namespace Ray2
5 | {
6 | public interface IRayBuilder
7 | {
8 | IServiceCollection Services { get; }
9 | IConfiguration Configuration { get; }
10 | void Build();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/DependencyInjection/RayBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using Ray2.Configuration;
4 | using Ray2.Configuration.Creator;
5 | using Ray2.Configuration.Validator;
6 | using Ray2.EventProcess;
7 | using Ray2.EventSource;
8 | using Ray2.MQ;
9 | using Ray2.Serialization;
10 | using Orleans.Runtime;
11 | using Ray2.Internal;
12 |
13 | namespace Ray2
14 | {
15 | public class RayBuilder : IRayBuilder
16 | {
17 | public IServiceCollection Services { get; }
18 | public IConfiguration Configuration { get; }
19 | public RayBuilder(IServiceCollection services, IConfiguration configuration)
20 | {
21 | this.Configuration = configuration;
22 | this.Services = services;
23 | }
24 | public void Build()
25 | {
26 | this.AddCoreServices();
27 |
28 | this.AddConfigurationServices();
29 |
30 | this.AddInternalConfiguration();
31 | }
32 |
33 | private void AddCoreServices()
34 | {
35 | this.Services.AddOptions();
36 | this.Services.AddTransient(typeof(IEventSourcing<,>), typeof(EventSourcing<,>));
37 | this.Services.AddTransient();
38 | this.Services.AddTransient(typeof(IEventProcessCore<,>), typeof(EventProcessCore<,>));
39 | this.Services.AddTransient();
40 |
41 | this.Services.AddSingleton();
42 | this.Services.AddSingleton();
43 | this.Services.AddSingleton();
44 | this.Services.AddSingleton();
45 | this.Services.AddSingletonNamedService(SerializationType.JsonUTF8);
46 | }
47 |
48 | private void AddConfigurationServices()
49 | {
50 | this.Services.AddSingleton();
51 | this.Services.AddSingleton();
52 | this.Services.AddSingleton();
53 | this.Services.AddSingleton();
54 | this.Services.AddSingleton();
55 |
56 | this.Services.AddSingleton();
57 | this.Services.AddSingleton();
58 | this.Services.AddSingleton();
59 | this.Services.AddSingleton();
60 | this.Services.AddSingleton();
61 | }
62 |
63 | private void AddInternalConfiguration()
64 | {
65 | var configuration = new InternalConfigurationCreator().Create();
66 | this.Services.AddSingleton(configuration);
67 | this.Services.BuildServiceProvider().GetRequiredService().IsValid(configuration);
68 |
69 | //Inject the Processor into the DI system
70 | var processList = configuration.EventProcessOptionsList;
71 | if (processList == null || processList.Count == 0)
72 | return;
73 | foreach (var p in processList)
74 | {
75 | if (p.ProcessorType == ProcessorType.SimpleProcessor)
76 | {
77 | this.Services.AddSingleton(p.ProcessorHandle);
78 | }
79 | }
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/DependencyInjection/RaySiloHostBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using Orleans.Runtime;
4 | using Ray2;
5 | using Ray2.Configuration.Validator;
6 | using Ray2.MQ;
7 | using System;
8 |
9 | namespace Orleans.Hosting
10 | {
11 | public static class RaySiloHostBuilderExtensions
12 | {
13 | ///
14 | /// Use Ray
15 | ///
16 | ///
17 | /// Ray and Ray module configuration
18 | /// Provide a action for building Ray
19 | ///
20 | public static ISiloHostBuilder UseRay(this ISiloHostBuilder hostBuilder, Action builder)
21 | {
22 | hostBuilder.ConfigureServices((HostBuilderContext build, IServiceCollection services) =>
23 | {
24 |
25 | services.AddRay(build.Configuration, builder);
26 | });
27 | hostBuilder.EnableDirectClient();
28 | hostBuilder.AddStartupTask((sp,cancellationToken)=>
29 | {
30 | return sp.GetRequiredService().Start();
31 | });
32 | return hostBuilder;
33 | }
34 |
35 | ///
36 | /// Add Ray
37 | ///
38 | ///
39 | /// Ray and Ray module configuration
40 | /// Provide a action for building Ray
41 | ///
42 | internal static IServiceCollection AddRay(this IServiceCollection services, IConfiguration configuration, Action builder)
43 | {
44 | services.AddSingleton(typeof(IKeyedServiceCollection<,>), typeof(KeyedServiceCollection<,>));
45 | services.AddLogging();
46 | var build = new RayBuilder(services, configuration);
47 | if (builder == null)
48 | {
49 | throw new RayConfigurationException("Did not inject MQ providers and Storage providers into Ray");
50 | }
51 | builder.Invoke(build);
52 |
53 | //Ray builder
54 | build.Build();
55 | return services;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/EventInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ray2.Configuration
6 | {
7 | ///
8 | /// Ray event information
9 | ///
10 | public class EventInfo
11 | {
12 | ///
13 | /// The name of the event
14 | ///
15 | public string Name { get; set; }
16 | ///
17 | /// Type of event
18 | ///
19 | public Type Type { get; set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/EventProcessOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Ray2.Configuration
5 | {
6 | public class EventProcessOptions
7 | {
8 | public EventProcessOptions(string processorName, string processorFullName, ProcessorType processorType, Type processorHandle, string eventSourceName, int onceProcessCount, TimeSpan onceProcessTimeout, StatusOptions statusOptions, IList subscribeOptions)
9 | {
10 | this.ProcessorName = processorName;
11 | this.ProcessorFullName = processorFullName;
12 | this.EventSourceName = eventSourceName;
13 | this.OnceProcessCount = onceProcessCount;
14 | this.OnceProcessTimeout = onceProcessTimeout;
15 | this.StatusOptions = statusOptions;
16 | this.SubscribeOptions = subscribeOptions;
17 | this.ProcessorType = processorType;
18 | this.ProcessorHandle = processorHandle;
19 | }
20 | public string ProcessorName { get; private set; }
21 | public string EventSourceName { get; private set; }
22 | public string ProcessorFullName { get; private set; }
23 | public ProcessorType ProcessorType { get; private set; }
24 | public Type ProcessorHandle { get; private set; }
25 | public int OnceProcessCount { get; private set; }
26 | public TimeSpan OnceProcessTimeout { get; private set; }
27 | public StatusOptions StatusOptions { get; private set; }
28 | public IList SubscribeOptions { get; private set; }
29 | }
30 |
31 | ///
32 | /// Event processor type
33 | ///
34 | public enum ProcessorType
35 | {
36 | GrainProcessor,
37 | SimpleProcessor
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/EventPublishOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ray2.Configuration
6 | {
7 | public class EventPublishOptions
8 | {
9 | public EventPublishOptions(string topic, string mqProvider,string fullName)
10 | {
11 | this.Topic = topic;
12 | this.MQProvider = mqProvider;
13 | this.EventPublishFullName = fullName;
14 | }
15 | public string EventPublishFullName { get; private set; }
16 | public string Topic { get; private set; }
17 | public string MQProvider { get; private set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/EventSourceOptions.cs:
--------------------------------------------------------------------------------
1 | using Ray2.Storage;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace Ray2.Configuration
7 | {
8 | public class EventSourceOptions
9 | {
10 | public EventSourceOptions(string eventSourceName,string sourcingFullName, SnapshotOptions snapshotOptions , StorageOptions storageOptions)
11 | {
12 | this.EventSourceName = eventSourceName;
13 | this.SourcingFullName = sourcingFullName;
14 | this.SnapshotOptions = snapshotOptions;
15 | this.StorageOptions = storageOptions;
16 | }
17 | public string EventSourceName { get; private set; }
18 | public string SourcingFullName { get; private set; }
19 | public SnapshotOptions SnapshotOptions { get; private set; }
20 | public StorageOptions StorageOptions { get; private set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/EventSubscribeOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ray2.Configuration
6 | {
7 | public class EventSubscribeOptions
8 | {
9 | public EventSubscribeOptions(string mqProvider, string topic, string fullName)
10 | {
11 | this.MQProvider = mqProvider;
12 | this.Topic = topic;
13 | this.EventSubscribeFullName = fullName;
14 | }
15 | public string EventSubscribeFullName { get; private set; }
16 | public string MQProvider { get; private set; }
17 | public string Topic { get; private set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/IInternalConfiguration.cs:
--------------------------------------------------------------------------------
1 | using Ray2.EventProcess;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace Ray2.Configuration
7 | {
8 | ///
9 | /// Ray system internal configuration
10 | ///
11 | public interface IInternalConfiguration
12 | {
13 | ///
14 | /// Get all event source configurations
15 | ///
16 | ///
17 | IList EventSourceOptions { get; }
18 | ///
19 | /// Get all event publishing configurations
20 | ///
21 | ///
22 | IList EventPublishOptionsList { get; }
23 | ///
24 | /// Get all processor configurations
25 | ///
26 | ///
27 | IList EventProcessOptionsList { get; }
28 |
29 | ///
30 | /// Get the event type by name
31 | ///
32 | /// The name of the event
33 | /// event type
34 | ///
35 | bool GetEvenType(string name, out Type type);
36 | ///
37 | /// Get event information by name
38 | ///
39 | /// The name of the event
40 | ///
41 | EventInfo GetEvenInfo(string name);
42 | ///
43 | /// Get all event types
44 | ///
45 | ///
46 | IList GetEvenInfoList();
47 | ///
48 | /// Get the configuration of the event processor based on the event processor name
49 | ///
50 | /// The name of the event processor
51 | ///
52 | EventProcessOptions GetEventProcessOptions(string name);
53 | ///
54 | /// Get the event processor configuration based on the event processor
55 | ///
56 | /// processor
57 | ///
58 | EventProcessOptions GetEventProcessOptions(IEventProcessor eventProcessor);
59 |
60 | ///
61 | /// Get the event source configuration based on the event source name
62 | ///
63 | /// The name of the event source
64 | ///
65 | EventSourceOptions GetEventSourceOptions(string name);
66 | ///
67 | /// Get the event source configuration based on the event source
68 | ///
69 | /// Event source
70 | ///
71 | EventSourceOptions GetEventSourceOptions(IRay ray);
72 |
73 | ///
74 | /// Get the event publishing configuration in the event source
75 | ///
76 | /// Event source
77 | ///
78 | EventPublishOptions GetEventPublishOptions(IRay ray);
79 | ///
80 | /// Get the event publishing configuration in the event processor
81 | ///
82 | /// event
83 | ///
84 | EventPublishOptions GetEventPublishOptions(IEvent @event);
85 |
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/SnapshotOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ray2.Configuration
6 | {
7 | public class SnapshotOptions : StorageOptions
8 | {
9 | public SnapshotOptions(string storageProvider, string shardingStrategy, SnapshotType snapshotType)
10 | : base(storageProvider, shardingStrategy)
11 | {
12 | this.SnapshotType = snapshotType;
13 | }
14 |
15 | public SnapshotOptions()
16 | : base(null, null)
17 | {
18 | this.SnapshotType = SnapshotType.NoSnapshot;
19 | }
20 | public SnapshotType SnapshotType { get; private set; }
21 |
22 | }
23 | public enum SnapshotType
24 | {
25 | Synchronous,
26 | Asynchronous,
27 | NoSnapshot
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/StatusOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ray2.Configuration
6 | {
7 | public class StatusOptions : StorageOptions
8 | {
9 | public StatusOptions(string storageProvider, string shardingStrategy, StatusMode statusMode) : base(storageProvider, shardingStrategy)
10 | {
11 | this.StatusMode = statusMode;
12 | }
13 | public StatusMode StatusMode { get; private set; }
14 | }
15 |
16 | public enum StatusMode
17 | {
18 | Synchronous,
19 | Asynchronous
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/StorageOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ray2.Configuration
6 | {
7 | public class StorageOptions
8 | {
9 | public StorageOptions(string storageProvider,string shardingStrategy)
10 | {
11 | this.StorageProvider = storageProvider;
12 | this.ShardingStrategy = shardingStrategy;
13 | }
14 | public string StorageProvider { get; private set; }
15 | public string ShardingStrategy { get; private set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Validator/EventProcessOptionsFluentVaildator.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 | using Orleans.Runtime;
3 | using Ray2.Storage;
4 | using System;
5 | using System.Linq;
6 |
7 | namespace Ray2.Configuration.Validator
8 | {
9 | public class EventProcessOptionsFluentVaildator : AbstractValidator
10 | {
11 | private readonly IServiceProvider serviceProvider;
12 |
13 | public EventProcessOptionsFluentVaildator(IServiceProvider provider, EventSubscribeOptionsFluentVaildator eventSubscribeOptionsFluentVaildator)
14 | {
15 | this.serviceProvider = provider;
16 |
17 | base.RuleFor(x => x.ProcessorName)
18 | .NotEmpty()
19 | .WithMessage(x => $"EventProcessorAttribute.Name in {x.ProcessorFullName} cannot be empty");
20 |
21 | base.When(x => x.ProcessorType == ProcessorType.GrainProcessor, () =>
22 | {
23 | base.RuleFor(x => x.EventSourceName)
24 | .NotEmpty()
25 | .WithMessage(x => $"EventProcessorAttribute.EventSourceName in {x.ProcessorFullName} cannot be empty");
26 | });
27 |
28 | base.RuleFor(x => x.OnceProcessCount)
29 | .GreaterThan(0)
30 | .WithMessage(x => $"The EventProcessorAttribute.OnceProcessCount configuration in {x.ProcessorFullName} must be greater than zero");
31 |
32 | base.RuleFor(x => x.StatusOptions)
33 | .Must(x => !string.IsNullOrEmpty(x.ShardingStrategy) || !string.IsNullOrEmpty(x.StorageProvider))
34 | .WithMessage(x => $" Need to configure EventProcessorAttribute.StorageProvider or EventProcessorAttribute.ShardingStrategy storage provider in {x.ProcessorFullName}");
35 |
36 | base.When(x => !string.IsNullOrEmpty(x.StatusOptions.ShardingStrategy), () =>
37 | {
38 | base.RuleFor(x => x.StatusOptions.ShardingStrategy)
39 | .Must(this.HavaShardingStrategyRegistered)
40 | .WithMessage("{PropertyValue} IStorageSharding is not injected into the Ray");
41 | });
42 | base.When(x => !string.IsNullOrEmpty(x.StatusOptions.StorageProvider), () =>
43 | {
44 | base.RuleFor(x => x.StatusOptions.StorageProvider)
45 | .Must(this.HavaStateStorageProviderRegistered)
46 | .WithMessage("{PropertyValue} IEventStorage provider is not injected into the Ray");
47 | });
48 |
49 | base.RuleFor(x => x.SubscribeOptions.Count())
50 | .GreaterThan(0)
51 | .WithMessage(x => $"{x.ProcessorFullName} is not configured with EventSubscribeAttribute and cannot be subscribed to");
52 | base.RuleForEach(x => x.SubscribeOptions)
53 | .SetValidator(eventSubscribeOptionsFluentVaildator);
54 |
55 | }
56 |
57 | private bool HavaStateStorageProviderRegistered(string storageProvider)
58 | {
59 | var provider = this.serviceProvider.GetServiceByName(storageProvider);
60 | return provider != null;
61 | }
62 |
63 | private bool HavaShardingStrategyRegistered(string shardingStrategy)
64 | {
65 | var provider = this.serviceProvider.GetServiceByName(shardingStrategy);
66 | return provider != null;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Validator/EventPublishOptionsFluentVaildator.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 | using Orleans.Runtime;
3 | using Ray2.MQ;
4 | using System;
5 |
6 | namespace Ray2.Configuration.Validator
7 | {
8 | public class EventPublishOptionsFluentVaildator : AbstractValidator
9 | {
10 | private readonly IServiceProvider serviceProvider;
11 | public EventPublishOptionsFluentVaildator(IServiceProvider provider)
12 | {
13 | this.serviceProvider = provider;
14 |
15 | base.RuleFor(x => x.MQProvider)
16 | .NotEmpty()
17 | .WithMessage(x=>$"EventPublishAttribute.MQProvider in {x.EventPublishFullName} cannot be empty");
18 |
19 | base.RuleFor(x => x.MQProvider)
20 | .Must(this.HaveMQProviderRegistered)
21 | .WithMessage("{PropertyValue} MQ provider is not injected into the Ray");
22 |
23 | base.RuleFor(x => x.Topic)
24 | .NotEmpty()
25 | .WithMessage(x=> $"EventPublishAttribute.MQTopic in {x.EventPublishFullName} cannot be empty");
26 | }
27 |
28 | private bool HaveMQProviderRegistered(string MQProvider)
29 | {
30 | var provider = this.serviceProvider.GetServiceByName(MQProvider);
31 | return provider != null;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Validator/EventSourceOptionsFluentVaildator.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 | using Orleans.Runtime;
3 | using Ray2.Storage;
4 | using System;
5 |
6 | namespace Ray2.Configuration.Validator
7 | {
8 | public class EventSourceOptionsFluentVaildator : AbstractValidator
9 | {
10 | private readonly IServiceProvider serviceProvider;
11 | public EventSourceOptionsFluentVaildator(IServiceProvider provider)
12 | {
13 | this.serviceProvider = provider;
14 |
15 | base.RuleFor(x => x.EventSourceName)
16 | .NotEmpty()
17 | .WithMessage(x => $"EventSourcingAttribute.Name in {x.SourcingFullName} cannot be empty");
18 |
19 | base.RuleFor(x => x.StorageOptions)
20 | .Must(x => !string.IsNullOrEmpty(x.ShardingStrategy) || !string.IsNullOrEmpty(x.StorageProvider))
21 | .WithMessage(x => $" Need to configure EventSourcingAttribute.StorageProvider or EventSourcingAttribute.ShardingStrategy storage provider in {x.SourcingFullName}");
22 | base.When(x => !string.IsNullOrEmpty(x.StorageOptions.ShardingStrategy), () =>
23 | {
24 | base.RuleFor(x => x.StorageOptions.ShardingStrategy)
25 | .Must(this.HavaShardingStrategyRegistered)
26 | .WithMessage("{PropertyValue} IStorageSharding is not injected into the Ray");
27 | });
28 | base.When(x => !string.IsNullOrEmpty(x.StorageOptions.StorageProvider), () =>
29 | {
30 | base.RuleFor(x => x.StorageOptions.StorageProvider)
31 | .Must(this.HavaEventStorageProviderRegistered)
32 | .WithMessage("{PropertyValue} IEventStorage provider is not injected into the Ray");
33 | });
34 |
35 | base.When(x => x.SnapshotOptions.SnapshotType != SnapshotType.NoSnapshot, () =>
36 | {
37 | //base.RuleFor(x => x.SnapshotOptions)
38 | // .Must(x => string.IsNullOrEmpty(x.ShardingStrategy) && string.IsNullOrEmpty(x.StorageProvider))
39 | // .WithMessage(x => $" Need to configure EventSourcingAttribute.StorageProvider or EventSourcingAttribute.ShardingStrategy storage provider in {x.SourcingFullName}");
40 |
41 | base.When(x => !string.IsNullOrEmpty(x.SnapshotOptions.ShardingStrategy), () =>
42 | {
43 | base.RuleFor(x => x.SnapshotOptions.ShardingStrategy)
44 | .Must(this.HavaShardingStrategyRegistered)
45 | .WithMessage("{PropertyValue} IStorageSharding is not injected into the Ray");
46 | });
47 | base.When(x => !string.IsNullOrEmpty(x.SnapshotOptions.StorageProvider), () =>
48 | {
49 | base.RuleFor(x => x.SnapshotOptions.StorageProvider)
50 | .Must(this.HavaSnapshotStorageProviderRegistered)
51 | .WithMessage("{PropertyValue} IStateStorage provider is not injected into the Ray");
52 | });
53 | });
54 | }
55 |
56 | private bool HavaEventStorageProviderRegistered(string storageProvider)
57 | {
58 | var provider = this.serviceProvider.GetServiceByName(storageProvider);
59 | return provider != null;
60 | }
61 |
62 | private bool HavaSnapshotStorageProviderRegistered(string storageProvider)
63 | {
64 | var provider = this.serviceProvider.GetServiceByName(storageProvider);
65 | return provider != null;
66 | }
67 |
68 | private bool HavaShardingStrategyRegistered(string shardingStrategy)
69 | {
70 | var provider = this.serviceProvider.GetServiceByName(shardingStrategy);
71 | return provider != null;
72 | }
73 |
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Validator/EventSubscribeOptionsFluentVaildator.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 | using Orleans.Runtime;
3 | using Ray2.MQ;
4 | using System;
5 |
6 | namespace Ray2.Configuration.Validator
7 | {
8 | public class EventSubscribeOptionsFluentVaildator : AbstractValidator
9 | {
10 | private readonly IServiceProvider serviceProvider;
11 | public EventSubscribeOptionsFluentVaildator(IServiceProvider provider)
12 | {
13 | this.serviceProvider = provider;
14 |
15 | base.RuleFor(x => x.MQProvider)
16 | .NotEmpty()
17 | .WithMessage(x => $"EventSubscribeAttribute.MQProvider in {x.EventSubscribeFullName} cannot be empty");
18 |
19 | base.RuleFor(x => x.MQProvider)
20 | .Must(this.HaveMQProviderRegistered)
21 | .WithMessage("{PropertyValue} MQ provider is not injected into the Ray");
22 |
23 | base.RuleFor(x => x.Topic)
24 | .NotEmpty()
25 | .WithMessage(x => $"EventSubscribeAttribute.Topic in {x.EventSubscribeFullName} cannot be empty");
26 |
27 | }
28 |
29 |
30 | private bool HaveMQProviderRegistered(string MQProvider)
31 | {
32 | var provider = this.serviceProvider.GetServiceByName(MQProvider);
33 | return provider != null;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Validator/IInternalConfigurationValidator.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace Ray2.Configuration.Validator
4 | {
5 | public interface IInternalConfigurationValidator
6 | {
7 | void IsValid(InternalConfiguration configuration);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Validator/InternalConfigurationFluentVaildator.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 |
5 | namespace Ray2.Configuration.Validator
6 | {
7 | public class InternalConfigurationFluentVaildator : AbstractValidator, IInternalConfigurationValidator
8 | {
9 | public InternalConfigurationFluentVaildator(EventProcessOptionsFluentVaildator eventProcessOptionsFluentVaildator, EventSourceOptionsFluentVaildator eventSourceOptionsFluentVaildator, EventPublishOptionsFluentVaildator eventPublishOptionsFluentVaildator)
10 | {
11 | //Determine if the event processor name is duplicated
12 | base.RuleFor(f => f.EventProcessOptionsList.GroupBy(t => t.ProcessorName).Where(t => t.Count() > 1).FirstOrDefault())
13 | .Null()
14 | .WithMessage((optionsList, options) => $"{options.Key} event processor name is repeatedly configured and cannot be repeated");
15 |
16 | //Determine whether the event source name is duplicated
17 | base.RuleFor(f => f.EventSourceOptions.GroupBy(t => t.EventSourceName).Where(t => t.Count() > 1).FirstOrDefault())
18 | .Null()
19 | .WithMessage((optionsList, options) => $"Event source name {options.Key} repeat configuration");
20 |
21 | base.RuleForEach(f => f.EventSourceOptions)
22 | .SetValidator(eventSourceOptionsFluentVaildator);
23 |
24 | base.RuleForEach(f => f.EventProcessOptionsList)
25 | .SetValidator(eventProcessOptionsFluentVaildator);
26 |
27 | base.RuleForEach(f => f.EventProcessOptionsList)
28 | .Must((options, processOptions) => this.ProcessHavaEventSource(options, processOptions))
29 | .WithMessage((options, processOptions) => $"Configuration in {processOptions.ProcessorFullName} EventProcessorAttribute.EventSourceName Value {processOptions.EventSourceName} Cannot find the event source configuration for ");
30 |
31 | base.RuleForEach(f => f.EventPublishOptionsList)
32 | .SetValidator(eventPublishOptionsFluentVaildator);
33 | }
34 | private bool ProcessHavaEventSource(InternalConfiguration configuration, EventProcessOptions eventProcessOptions)
35 | {
36 | if (eventProcessOptions.ProcessorType == ProcessorType.SimpleProcessor)
37 | return true;
38 |
39 | var es = configuration.GetEventSourceOptions(eventProcessOptions.EventSourceName);
40 | if (es == null)
41 | return false;
42 | else
43 | return true;
44 | }
45 |
46 | public void IsValid(InternalConfiguration configuration)
47 | {
48 | var validateResult = this.Validate(configuration);
49 | if (validateResult.IsValid)
50 | {
51 | return;
52 | }
53 | var error = validateResult.Errors.FirstOrDefault();
54 | throw new RayConfigurationException("Ray configuration error : " + error.ErrorMessage);
55 | }
56 |
57 |
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Ray2/Configuration/Validator/RayConfigurationException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Ray2.Configuration.Validator
4 | {
5 | public class RayConfigurationException : Exception
6 | {
7 | public RayConfigurationException(string message) : base(message)
8 | {
9 |
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Ray2/Event.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Runtime.Serialization;
5 | using System.Text;
6 |
7 | namespace Ray2
8 | {
9 | ///
10 | /// Event abstract class
11 | ///
12 | /// StateId Type
13 | public abstract class Event : IEvent
14 | {
15 | public Event()
16 | {
17 | this.TypeCode = this.GetType().FullName;
18 | this.Timestamp = this.GetCurrentTimeUnix();
19 | }
20 | ///
21 | /// Event abstract class
22 | ///
23 | /// Relation Event
24 | public Event(IEvent @event) : this()
25 | {
26 | this.RelationEvent = @event.GetRelationKey();
27 | }
28 | ///
29 | /// State Id
30 | ///
31 | public virtual TStateKey StateId { get; set; }
32 | ///
33 | /// the version number of
34 | ///
35 | public virtual long Version { get; set; }
36 | ///
37 | /// Event release timestamp
38 | ///
39 | [JsonProperty]
40 | public virtual long Timestamp { get; private set; }
41 | ///
42 | /// Event type fullname
43 | ///
44 | [JsonProperty]
45 | public virtual string TypeCode { get; private set; }
46 | ///
47 | /// Relation Event
48 | ///
49 | public virtual string RelationEvent { get; set; }
50 | ///
51 | /// Generate Relation key
52 | ///
53 | ///
54 | public string GetRelationKey()
55 | {
56 | return $"{StateId}-{TypeCode}-{Version}";
57 | }
58 | ///
59 | /// Get StateId
60 | ///
61 | ///
62 | public object GetStateId()
63 | {
64 | return this.StateId;
65 | }
66 | public override string ToString()
67 | {
68 | return $"TypeCode:{TypeCode},StateId:{StateId},VersionNo:{Version},Timestamp:{Timestamp}";
69 | }
70 |
71 |
72 | public long GetCurrentTimeUnix()
73 | {
74 | TimeSpan cha = (DateTime.Now - TimeZoneInfo.ConvertTimeToUtc(new System.DateTime(1970, 1, 1)));
75 | long t = (long)cha.TotalMilliseconds;
76 | return t;
77 | }
78 |
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Ray2/EventProcess/EventProcessExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Ray2.Configuration;
3 | using System;
4 |
5 | namespace Ray2.EventProcess
6 | {
7 | public static class EventProcessExtensions
8 | {
9 | public static IEventProcessCore GetEventProcessCore(this IServiceProvider serviceProvider, string ProcessorName)
10 | {
11 | var internalConfiguration = serviceProvider.GetRequiredService();
12 | var options = internalConfiguration.GetEventProcessOptions(ProcessorName);
13 | return serviceProvider.GetEventProcessCore(options);
14 | }
15 |
16 | public static IEventProcessCore GetEventProcessCore(this IServiceProvider serviceProvider, IEventProcessor eventProcessor)
17 | {
18 | var internalConfiguration = serviceProvider.GetRequiredService();
19 | var options = internalConfiguration.GetEventProcessOptions(eventProcessor);
20 | return serviceProvider.GetEventProcessCore(options);
21 | }
22 | private static IEventProcessCore GetEventProcessCore(this IServiceProvider serviceProvider, EventProcessOptions options)
23 | {
24 | var eventProcessCore = serviceProvider.GetRequiredService();
25 | eventProcessCore.Options = options;
26 | return eventProcessCore;
27 | }
28 |
29 | public static IEventProcessCore GetEventProcessCore(this IServiceProvider serviceProvider, string ProcessorName)
30 | where TState : IState, new()
31 | {
32 | var internalConfiguration = serviceProvider.GetRequiredService();
33 | var options = internalConfiguration.GetEventProcessOptions(ProcessorName);
34 | return serviceProvider.GetEventProcessCore(options);
35 | }
36 |
37 | public static IEventProcessCore GetEventProcessCore(this IServiceProvider serviceProvider, IEventProcessor eventProcessor)
38 | where TState : IState, new()
39 | {
40 | var internalConfiguration = serviceProvider.GetRequiredService();
41 | var options = internalConfiguration.GetEventProcessOptions(eventProcessor);
42 | return serviceProvider.GetEventProcessCore(options);
43 | }
44 |
45 | private static IEventProcessCore GetEventProcessCore(this IServiceProvider serviceProvider, EventProcessOptions options)
46 | where TState : IState, new()
47 | {
48 | var eventProcessCore = serviceProvider.GetRequiredService>();
49 | eventProcessCore.Options = options;
50 | return eventProcessCore;
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Ray2/EventProcess/EventProcessState.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.Serialization;
2 |
3 | namespace Ray2.EventProcess
4 | {
5 | ///
6 | /// Status of event processing, record processing version number time,
7 | /// etc.
8 | ///
9 | ///
10 | [DataContract]
11 | public class EventProcessState : State
12 | {
13 | protected override void PlayEvent(IEvent @event)
14 | {
15 | return;
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Ray2/EventProcess/EventProcessorFactory.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Microsoft.Extensions.Logging;
3 | using Ray2.Configuration;
4 | using System;
5 |
6 | namespace Ray2.EventProcess
7 | {
8 | public class EventProcessorFactory : IEventProcessorFactory
9 | {
10 | private readonly IServiceProvider _serviceProvider;
11 | private readonly IInternalConfiguration _configuration;
12 | private readonly ILogger _logger;
13 | public EventProcessorFactory(IInternalConfiguration configuration, IServiceProvider serviceProvider, ILogger logger)
14 | {
15 | this._configuration = configuration;
16 | this._serviceProvider = serviceProvider;
17 | this._logger = logger;
18 | }
19 | public IEventProcessor Create(string processName)
20 | {
21 | var options = this._configuration.GetEventProcessOptions(processName);
22 | if (options == null)
23 | {
24 | throw new Exception($"Did not find the configuration of the {processName} processor ");
25 | }
26 | if (options.ProcessorType == ProcessorType.GrainProcessor)
27 | {
28 | return new EventProcessorGrainDispatch(options.ProcessorFullName, _serviceProvider);
29 | }
30 | else
31 | {
32 | return (IEventProcessor)_serviceProvider.GetRequiredService(options.ProcessorHandle);
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Ray2/EventProcess/EventProcessorGrainDispatch.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Orleans;
3 | using Ray2.EventSource;
4 | using System;
5 | using System.Threading.Tasks;
6 |
7 | namespace Ray2.EventProcess
8 | {
9 | public class EventProcessorGrainDispatch : IEventProcessor
10 | {
11 | private readonly string _grainClassName;
12 | private readonly IServiceProvider _serviceProvider;
13 | private readonly IClusterClient client;
14 | public EventProcessorGrainDispatch(string grainClassName, IServiceProvider serviceProvider)
15 | {
16 | this._grainClassName = grainClassName;
17 | this._serviceProvider = serviceProvider;
18 | this.client = serviceProvider.GetRequiredService();
19 | }
20 | public Task Tell(EventModel model)
21 | {
22 | object id = model.Event.GetStateId();
23 | IEventProcessor eventProcessor;
24 | if (id is Guid _guid)
25 | {
26 | eventProcessor = client.GetGrain(primaryKey: _guid, grainClassNamePrefix: _grainClassName);
27 | }
28 | else if (id is long _id)
29 | {
30 | eventProcessor = client.GetGrain(primaryKey: _id, grainClassNamePrefix: _grainClassName);
31 | }
32 | else
33 | {
34 | eventProcessor = client.GetGrain(primaryKey: id.ToString(), grainClassNamePrefix: _grainClassName);
35 | }
36 | return eventProcessor.Tell(model);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Ray2/EventProcess/IEventProcessCore.cs:
--------------------------------------------------------------------------------
1 | using Ray2.Configuration;
2 | using Ray2.EventSource;
3 | using System;
4 | using System.Threading.Tasks;
5 |
6 | namespace Ray2.EventProcess
7 | {
8 | using EventProcessor = Func;
9 | public interface IEventProcessCore
10 | {
11 | EventProcessOptions Options { get; set; }
12 | Task Init(EventProcessor eventProcessor);
13 | Task Tell(EventModel model);
14 | }
15 |
16 |
17 | public interface IEventProcessCore : IEventProcessCore
18 | where TState : IState, new()
19 | {
20 | Task> Init(TStateKey stateKey, EventProcessor eventProcessor);
21 | Task SaveStateAsync();
22 | Task ReadStateAsync();
23 | Task ClearStateAsync();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Ray2/EventProcess/IEventProcessor.cs:
--------------------------------------------------------------------------------
1 | using Orleans;
2 | using Ray2.EventSource;
3 | using System.Threading.Tasks;
4 |
5 | namespace Ray2.EventProcess
6 | {
7 | ///
8 | /// This is the Event process interface
9 | ///
10 | public interface IEventProcessor : IGrainWithGuidKey, IGrainWithIntegerKey, IGrainWithStringKey
11 | {
12 | Task Tell(EventModel model);
13 | }
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/src/Ray2/EventProcess/IEventProcessorFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ray2.EventProcess
6 | {
7 | public interface IEventProcessorFactory
8 | {
9 | IEventProcessor Create(string processName);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Ray2/EventSource/EventModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Ray2.EventSource
4 | {
5 | public class EventModel
6 | {
7 | public EventModel(IEvent @event, string typeCode, long version)
8 | {
9 | Event = @event;
10 | TypeCode = typeCode;
11 | Version = version;
12 | StateId = @event.GetStateId();
13 | }
14 | public EventModel(IEvent @event):this(@event, @event.TypeCode, @event.Version)
15 | {
16 |
17 | }
18 | public IEvent Event { get; }
19 | public string TypeCode { get; }
20 | public Int64 Version { get; }
21 | public object StateId { get; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Ray2/EventSource/EventSourceExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Ray2.Configuration;
3 | using System;
4 |
5 | namespace Ray2.EventSource
6 | {
7 | public static class EventSourceExtensions
8 | {
9 | public static IEventSourcing GetEventSourcing(this IServiceProvider serviceProvider, string eventSourceName)
10 | {
11 | var internalConfiguration = serviceProvider.GetRequiredService();
12 | var options = internalConfiguration.GetEventSourceOptions(eventSourceName);
13 | return serviceProvider.GetEventSourcing(options);
14 | }
15 |
16 | public static IEventSourcing GetEventSourcing(this IServiceProvider serviceProvider, IRay ray)
17 | {
18 | var internalConfiguration = serviceProvider.GetRequiredService();
19 | var options = internalConfiguration.GetEventSourceOptions(ray);
20 | return serviceProvider.GetEventSourcing(options);
21 | }
22 |
23 | private static IEventSourcing GetEventSourcing(this IServiceProvider serviceProvider, EventSourceOptions options)
24 | {
25 | var eventSourcing = serviceProvider.GetRequiredService();
26 | eventSourcing.Options = options;
27 | return eventSourcing;
28 | }
29 |
30 | public static IEventSourcing GetEventSourcing(this IServiceProvider serviceProvider, string eventSourceName)
31 | where TState : IState, new()
32 | {
33 | var internalConfiguration = serviceProvider.GetRequiredService();
34 | var options = internalConfiguration.GetEventSourceOptions(eventSourceName);
35 | return serviceProvider.GetEventSourcing(options);
36 | }
37 |
38 | public static IEventSourcing GetEventSourcing(this IServiceProvider serviceProvider, IRay ray)
39 | where TState : IState, new()
40 | {
41 | var internalConfiguration = serviceProvider.GetRequiredService();
42 | var options = internalConfiguration.GetEventSourceOptions(ray);
43 | return serviceProvider.GetEventSourcing(options);
44 | }
45 |
46 | private static IEventSourcing GetEventSourcing(this IServiceProvider serviceProvider, EventSourceOptions options)
47 | where TState : IState, new()
48 | {
49 | var eventSourcing = serviceProvider.GetRequiredService>();
50 | eventSourcing.Options = options;
51 | return eventSourcing;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Ray2/EventSource/EventTransactionModel.cs:
--------------------------------------------------------------------------------
1 | using Ray2.MQ;
2 |
3 | namespace Ray2.EventSource
4 | {
5 | public class EventTransactionModel
6 | {
7 | public EventTransactionModel(IEvent @event, MQPublishType publishType)
8 | {
9 | this.Event = @event;
10 | this.PublishType = publishType;
11 | }
12 | ///
13 | /// Event
14 | ///
15 | public IEvent Event { get;}
16 | ///
17 | /// MQ publish type
18 | ///
19 | public MQPublishType PublishType { get; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Ray2/EventSource/IEventSourcing.cs:
--------------------------------------------------------------------------------
1 | using Ray2.Configuration;
2 | using Ray2.Storage;
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 |
6 | namespace Ray2.EventSource
7 | {
8 | ///
9 | /// This is the event source interface
10 | ///
11 | public interface IEventSourcing
12 | {
13 | EventSourceOptions Options { get; set; }
14 | Task> GetListAsync(EventQueryModel queryModel);
15 | Task ClearSnapshotAsync(string stateId);
16 | }
17 |
18 | ///
19 | /// This is the event source interface
20 | ///
21 | public interface IEventSourcing : IEventSourcing
22 | where TState : IState, new()
23 | {
24 |
25 | Task> Init(TStateKey stateKey);
26 | Task SaveAsync(IEvent @event);
27 | Task SaveAsync(IList> events);
28 | new Task>> GetListAsync(EventQueryModel queryModel);
29 |
30 | Task ReadSnapshotAsync();
31 | Task SaveSnapshotAsync(TState state);
32 | Task ClearSnapshotAsync();
33 |
34 | }
35 |
36 |
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/Ray2/EventSource/IEventTransaction.cs:
--------------------------------------------------------------------------------
1 | using Ray2.MQ;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 |
5 | namespace Ray2.EventSource
6 | {
7 | ///
8 | /// Transaction batch event
9 | ///
10 | ///
11 | ///
12 | public interface IEventTransaction : IEventTransaction
13 | {
14 | ///
15 | /// Transaction copy status
16 | ///
17 | TState State { get; }
18 | ///
19 | /// Write events to a transaction
20 | ///
21 | /// event
22 | void WriteEventAsync(EventTransactionModel model);
23 | ///
24 | /// Write events to a transaction
25 | ///
26 | /// event
27 | /// Whether to publish to mq
28 | void WriteEventAsync(IEvent @event, MQPublishType publishType = MQPublishType.Asynchronous);
29 | ///
30 | /// Write events to a transaction
31 | ///
32 | /// event list
33 | /// Whether to publish to mq
34 | void WriteEventAsync(IList> events, MQPublishType publishType = MQPublishType.Asynchronous);
35 | }
36 | ///
37 | /// Transaction batch event
38 | ///
39 | public interface IEventTransaction
40 | {
41 | TransactionState TransactionState { get; }
42 | ///
43 | /// Transaction volume
44 | ///
45 | ///
46 | int Count();
47 | ///
48 | /// Commit transaction
49 | ///
50 | ///
51 | Task Commit();
52 | ///
53 | /// roll back transaction
54 | ///
55 | void Rollback();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Ray2/IEvent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ray2
6 | {
7 | ///
8 | /// This is the event data interface
9 | ///
10 | public interface IEvent
11 | {
12 | ///
13 | /// the version number of
14 | ///
15 | Int64 Version { get; set; }
16 | ///
17 | /// Event release timestamp
18 | ///
19 | long Timestamp { get; }
20 | ///
21 | /// Event type fullname
22 | ///
23 | string TypeCode { get; }
24 | ///
25 | /// Related event
26 | ///
27 | string RelationEvent { get; }
28 | ///
29 | /// Generate Relation key
30 | ///
31 | ///
32 | string GetRelationKey();
33 | ///
34 | /// Get StateId
35 | ///
36 | ///
37 | object GetStateId();
38 | }
39 | ///
40 | /// This is the event data interface
41 | ///
42 | public interface IEvent: IEvent
43 | {
44 | ///
45 | /// State Id
46 | ///
47 | TPrimaryKey StateId { get; set; }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Ray2/IRay.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ray2
6 | {
7 | public interface IRay
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/Ray2/IState.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace Ray2
7 | {
8 | ///
9 | /// This is the state interface
10 | ///
11 | public interface IState
12 | {
13 | ///
14 | /// State version number
15 | ///
16 | Int64 Version { get; }
17 | ///
18 | /// Event time corresponding to the status version number
19 | ///
20 | long VersionTime { get; }
21 | ///
22 | /// State type fullname
23 | ///
24 | string TypeCode { get; }
25 | ///
26 | /// Play event modification status
27 | ///
28 | ///
29 | void Player(IEvent @event);
30 | ///
31 | /// Play event modification status
32 | ///
33 | ///
34 | void Player(IList events);
35 |
36 | ///
37 | /// next version no
38 | ///
39 | ///
40 | Int64 NextVersion();
41 | }
42 | ///
43 | /// This is the state interface
44 | ///
45 | public interface IState : IState
46 | {
47 | ///
48 | /// State Id
49 | ///
50 | TStateKey StateId { get; set; }
51 | ///
52 | /// Play event modification status
53 | ///
54 | ///
55 | void Player(IList> events);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Ray2/Internal/DataflowBufferBlock.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using System.Threading.Tasks.Dataflow;
5 |
6 | namespace Ray2.Internal
7 | {
8 | public class DataflowBufferBlock : IDataflowBufferBlock
9 | {
10 | private int isProcessing = 0;
11 | private readonly BufferBlock> dataflowChannel = new BufferBlock>();
12 | private readonly Func>, Task> processor;
13 |
14 | public int Count => dataflowChannel.Count;
15 |
16 | public DataflowBufferBlock(Func>, Task> processor)
17 | {
18 | this.processor = processor;
19 | }
20 | public Task SendAsync(TData data, bool isWallHandle)
21 | {
22 | return Task.Run(async () =>
23 | {
24 | var wrap = new DataflowBufferWrap(data);
25 | //First use the synchronous method to quickly write to the BufferBlock, if the failure is using the asynchronous method
26 | if (!dataflowChannel.Post(wrap))
27 | {
28 | if (!await dataflowChannel.SendAsync(wrap))
29 | {
30 | return false;
31 | }
32 | }
33 | if (isProcessing == 0)
34 | TriggerProcessor();
35 | if (!isWallHandle)
36 | return true;
37 | //Determine if you need to wait for processing
38 | return await wrap.Wall();
39 | });
40 | }
41 | public Task SendAsync(TData data)
42 | {
43 | return this.SendAsync(data, true);
44 | }
45 |
46 | public async void TriggerProcessor()
47 | {
48 | await Task.Run(async () =>
49 | {
50 | if (Interlocked.CompareExchange(ref isProcessing, 1, 0) == 1)
51 | return;
52 | try
53 | {
54 | while (await dataflowChannel.OutputAvailableAsync())
55 | {
56 | await this.processor(dataflowChannel);
57 | }
58 | }
59 | finally
60 | {
61 | Interlocked.Exchange(ref isProcessing, 0);
62 | }
63 | });
64 |
65 | }
66 |
67 |
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/Ray2/Internal/DataflowBufferBlockFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Concurrent;
3 | using System.Threading.Tasks;
4 | using System.Threading.Tasks.Dataflow;
5 |
6 | namespace Ray2.Internal
7 | {
8 | public class DataflowBufferBlockFactory : IDataflowBufferBlockFactory
9 | {
10 | ConcurrentDictionary DataflowBufferBlocks = new ConcurrentDictionary();
11 | public IDataflowBufferBlock Create(string name, Func>, Task> processor)
12 | where TData : class
13 | {
14 | return (IDataflowBufferBlock)DataflowBufferBlocks.GetOrAdd(name, (key) =>
15 | {
16 | return new DataflowBufferBlock(processor);
17 | });
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Ray2/Internal/DataflowBufferWrap.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 |
6 | namespace Ray2.Internal
7 | {
8 | public class DataflowBufferWrap