Skip to content

Commit 18a4020

Browse files
committed
Add basic first implementation of Event bus with rabbitMQ
1 parent 9b26253 commit 18a4020

12 files changed

Lines changed: 259 additions & 3 deletions

docker-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ services:
99
depends_on:
1010
- basket.data
1111
- identity.api
12+
- rabbitmq
1213

1314
catalog.api:
1415
image: eshop/catalog.api
@@ -17,6 +18,7 @@ services:
1718
dockerfile: Dockerfile
1819
depends_on:
1920
- sql.data
21+
- rabbitmq
2022

2123
identity.api:
2224
image: eshop/identity.api

eShopOnContainers-ServicesAndWebApps.sln

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-co
4848
EndProject
4949
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSPA", "src\Web\WebSPA\WebSPA.csproj", "{F16E3C6A-1C94-4EAB-BE91-099618060B68}"
5050
EndProject
51+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{47857844-D05A-4C37-BFB2-AF19B7EC418D}"
52+
EndProject
53+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "src\Services\Common\Infrastructure\Infrastructure.csproj", "{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}"
54+
EndProject
5155
Global
5256
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5357
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
@@ -494,6 +498,54 @@ Global
494498
{F16E3C6A-1C94-4EAB-BE91-099618060B68}.Release|x64.Build.0 = Release|Any CPU
495499
{F16E3C6A-1C94-4EAB-BE91-099618060B68}.Release|x86.ActiveCfg = Release|Any CPU
496500
{F16E3C6A-1C94-4EAB-BE91-099618060B68}.Release|x86.Build.0 = Release|Any CPU
501+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
502+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
503+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
504+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
505+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
506+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
507+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
508+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
509+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
510+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
511+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
512+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
513+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
514+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|Any CPU.Build.0 = Debug|Any CPU
515+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|ARM.ActiveCfg = Debug|Any CPU
516+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|ARM.Build.0 = Debug|Any CPU
517+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
518+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|iPhone.Build.0 = Debug|Any CPU
519+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
520+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
521+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|x64.ActiveCfg = Debug|Any CPU
522+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|x64.Build.0 = Debug|Any CPU
523+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|x86.ActiveCfg = Debug|Any CPU
524+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|x86.Build.0 = Debug|Any CPU
525+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
526+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
527+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|ARM.ActiveCfg = Debug|Any CPU
528+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|ARM.Build.0 = Debug|Any CPU
529+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
530+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|iPhone.Build.0 = Debug|Any CPU
531+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
532+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
533+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|x64.ActiveCfg = Debug|Any CPU
534+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|x64.Build.0 = Debug|Any CPU
535+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|x86.ActiveCfg = Debug|Any CPU
536+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|x86.Build.0 = Debug|Any CPU
537+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
538+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|Any CPU.Build.0 = Release|Any CPU
539+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|ARM.ActiveCfg = Release|Any CPU
540+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|ARM.Build.0 = Release|Any CPU
541+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|iPhone.ActiveCfg = Release|Any CPU
542+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|iPhone.Build.0 = Release|Any CPU
543+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
544+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
545+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|x64.ActiveCfg = Release|Any CPU
546+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|x64.Build.0 = Release|Any CPU
547+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|x86.ActiveCfg = Release|Any CPU
548+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|x86.Build.0 = Release|Any CPU
497549
EndGlobalSection
498550
GlobalSection(SolutionProperties) = preSolution
499551
HideSolutionNode = FALSE
@@ -516,5 +568,7 @@ Global
516568
{7796F5D8-31FC-45A4-B673-19DE5BA194CF} = {EF0337F2-ED00-4643-89FD-EE10863F1870}
517569
{A579E108-5445-403D-A407-339AC4D1611B} = {24CD3B53-141E-4A07-9B0D-796641E1CF78}
518570
{F16E3C6A-1C94-4EAB-BE91-099618060B68} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}
571+
{47857844-D05A-4C37-BFB2-AF19B7EC418D} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
572+
{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0} = {47857844-D05A-4C37-BFB2-AF19B7EC418D}
519573
EndGlobalSection
520574
EndGlobal

src/Services/Catalog/Catalog.API/Catalog.API.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@
5252
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
5353
</ItemGroup>
5454

55+
<ItemGroup>
56+
<ProjectReference Include="..\..\Common\Infrastructure\Infrastructure.csproj" />
57+
</ItemGroup>
58+
5559
<ItemGroup>
5660
<None Update="Dockerfile">
5761
<CopyToOutputDirectory>Always</CopyToOutputDirectory>

src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
44
using Microsoft.eShopOnContainers.Services.Catalog.API.Model;
55
using Microsoft.eShopOnContainers.Services.Catalog.API.ViewModel;
6+
using Microsoft.eShopOnContainers.Services.Common.Infrastructure;
7+
using Microsoft.eShopOnContainers.Services.Common.Infrastructure.Catalog;
68
using Microsoft.Extensions.Options;
79
using System.Collections.Generic;
810
using System.Linq;
@@ -15,11 +17,13 @@ public class CatalogController : ControllerBase
1517
{
1618
private readonly CatalogContext _context;
1719
private readonly IOptionsSnapshot<Settings> _settings;
20+
private readonly IEventBus _eventBus;
1821

19-
public CatalogController(CatalogContext context, IOptionsSnapshot<Settings> settings)
22+
public CatalogController(CatalogContext context, IOptionsSnapshot<Settings> settings, IEventBus eventBus)
2023
{
2124
_context = context;
2225
_settings = settings;
26+
_eventBus = eventBus;
2327

2428
((DbContext)context).ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
2529
}
@@ -41,7 +45,7 @@ public async Task<IActionResult> Items([FromQuery]int pageSize = 10, [FromQuery]
4145
itemsOnPage = ComposePicUri(itemsOnPage);
4246

4347
var model = new PaginatedItemsViewModel<CatalogItem>(
44-
pageIndex, pageSize, totalItems, itemsOnPage);
48+
pageIndex, pageSize, totalItems, itemsOnPage);
4549

4650
return Ok(model);
4751
}
@@ -99,7 +103,13 @@ public async Task<IActionResult> Items(int? catalogTypeId, int? catalogBrandId,
99103

100104
var model = new PaginatedItemsViewModel<CatalogItem>(
101105
pageIndex, pageSize, totalItems, itemsOnPage);
102-
106+
107+
//hook to run integration tests until POST methods are created
108+
if (catalogTypeId.HasValue && catalogTypeId == 1)
109+
{
110+
_eventBus.Publish(new CatalogPriceChanged());
111+
}
112+
103113
return Ok(model);
104114
}
105115

src/Services/Catalog/Catalog.API/Startup.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Microsoft.EntityFrameworkCore;
88
using Microsoft.EntityFrameworkCore.Infrastructure;
99
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
10+
using Microsoft.eShopOnContainers.Services.Common.Infrastructure;
1011
using Microsoft.Extensions.Configuration;
1112
using Microsoft.Extensions.DependencyInjection;
1213
using Microsoft.Extensions.Logging;
@@ -73,6 +74,8 @@ public void ConfigureServices(IServiceCollection services)
7374
.AllowCredentials());
7475
});
7576

77+
services.AddSingleton<IEventBus, EventBus>();
78+
7679
services.AddMvc();
7780
}
7881

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure.Catalog
6+
{
7+
public class CatalogPriceChanged : IIntegrationEvent
8+
{
9+
private readonly string _eventName = "catalogpricechanged";
10+
11+
public string Name {
12+
get
13+
{
14+
return _eventName;
15+
}
16+
}
17+
18+
public string Message { get { return "CatalogPriceChanged!!"; } }
19+
}
20+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure.Catalog
6+
{
7+
public class CatalogPriceChangedHandler : IIntegrationEventHandler<CatalogPriceChanged>
8+
{
9+
public void Handle(CatalogPriceChanged @event)
10+
{
11+
throw new NotImplementedException();
12+
}
13+
}
14+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+

2+
using Microsoft.eShopOnContainers.Services.Common.Infrastructure.Catalog;
3+
using RabbitMQ.Client;
4+
using RabbitMQ.Client.Events;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Text;
8+
9+
namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure
10+
{
11+
public class EventBus : IEventBus
12+
{
13+
private readonly Dictionary<string, List<IIntegrationEventHandler>> _handlers;
14+
private readonly Dictionary<string, Tuple<IModel, IConnection>> _listeners;
15+
16+
public EventBus()
17+
{
18+
_handlers = new Dictionary<string, List<IIntegrationEventHandler>>();
19+
_listeners = new Dictionary<string, Tuple<IModel, IConnection>>();
20+
}
21+
public void Publish(IIntegrationEvent @event)
22+
{
23+
var factory = new ConnectionFactory() { HostName = "172.20.0.1" };
24+
using (var connection = factory.CreateConnection())
25+
using (var channel = connection.CreateModel())
26+
{
27+
channel.QueueDeclare(queue: @event.Name,
28+
durable: false,
29+
exclusive: false,
30+
autoDelete: false,
31+
arguments: null);
32+
33+
string message = ((CatalogPriceChanged)@event).Message;
34+
var body = Encoding.UTF8.GetBytes(message);
35+
36+
channel.BasicPublish(exchange: "",
37+
routingKey: @event.Name,
38+
basicProperties: null,
39+
body: body);
40+
}
41+
42+
}
43+
44+
public void Subscribe<T>(IIntegrationEventHandler<T> handler) where T : IIntegrationEvent
45+
{
46+
var eventName = typeof(T).Name;
47+
if (_handlers.ContainsKey(eventName))
48+
{
49+
_handlers[eventName].Add(handler);
50+
}
51+
else
52+
{
53+
var factory = new ConnectionFactory() { HostName = "172.18.0.1" };
54+
var connection = factory.CreateConnection();
55+
var channel = connection.CreateModel();
56+
57+
channel.QueueDeclare(queue: eventName,
58+
durable: false,
59+
exclusive: false,
60+
autoDelete: false,
61+
arguments: null);
62+
63+
var consumer = new EventingBasicConsumer(channel);
64+
consumer.Received += (model, ea) =>
65+
{
66+
var body = ea.Body;
67+
var message = Encoding.UTF8.GetString(body);
68+
};
69+
channel.BasicConsume(queue: "hello",
70+
noAck: true,
71+
consumer: consumer);
72+
;
73+
74+
_listeners.Add(eventName, new Tuple<IModel, IConnection>(channel, connection));
75+
_handlers.Add(eventName, new List<IIntegrationEventHandler>());
76+
_handlers[eventName].Add(handler);
77+
}
78+
79+
}
80+
81+
public void Unsubscribe<T>(IIntegrationEventHandler<T> handler) where T : IIntegrationEvent
82+
{
83+
var eventName = typeof(T).Name;
84+
if (_handlers.ContainsKey(eventName) && _handlers[eventName].Contains(handler))
85+
{
86+
_handlers[eventName].Remove(handler);
87+
88+
if (_handlers[eventName].Count == 0)
89+
{
90+
_handlers.Remove(eventName);
91+
92+
var connectionItems =_listeners[eventName];
93+
_listeners.Remove(eventName);
94+
95+
connectionItems.Item1.Close();
96+
connectionItems.Item2.Close();
97+
}
98+
}
99+
}
100+
}
101+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure
6+
{
7+
public interface IEventBus
8+
{
9+
void Subscribe<T>(IIntegrationEventHandler<T> handler) where T: IIntegrationEvent;
10+
void Unsubscribe<T>(IIntegrationEventHandler<T> handler) where T : IIntegrationEvent;
11+
void Publish(IIntegrationEvent @event);
12+
}
13+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure
6+
{
7+
public interface IIntegrationEvent
8+
{
9+
string Name { get; }
10+
}
11+
}

0 commit comments

Comments
 (0)