mimi-messaging 0.1.9 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +66 -0
  4. data/README.md +68 -3
  5. data/TODO.md +8 -0
  6. data/docs/Messaging_Layer_Properties.md +141 -0
  7. data/docs/Why_HTTP_is_a_bad_choice.md +20 -0
  8. data/docs/diagrams/Pattern -- Command.drawio +1 -0
  9. data/docs/diagrams/Pattern -- Event direct.drawio +1 -0
  10. data/docs/diagrams/Pattern -- Event with Queue.drawio +1 -0
  11. data/docs/diagrams/Pattern -- Event.drawio +1 -0
  12. data/docs/diagrams/Pattern -- Query.drawio +1 -0
  13. data/docs/img/pattern--command.png +0 -0
  14. data/docs/img/pattern--event-direct.png +0 -0
  15. data/docs/img/pattern--event-using-queue.png +0 -0
  16. data/docs/img/pattern--event.png +0 -0
  17. data/docs/img/pattern--query.png +0 -0
  18. data/examples/basic_event_listener.rb +35 -0
  19. data/examples/basic_request_processor.rb +38 -0
  20. data/examples/using_messaging_low.rb +59 -0
  21. data/examples/using_pure_adapter.rb +62 -0
  22. data/lib/mimi/messaging.rb +429 -92
  23. data/lib/mimi/messaging/adapters.rb +22 -0
  24. data/lib/mimi/messaging/adapters/base.rb +233 -0
  25. data/lib/mimi/messaging/adapters/memory.rb +119 -0
  26. data/lib/mimi/messaging/adapters/test.rb +50 -0
  27. data/lib/mimi/messaging/errors.rb +24 -12
  28. data/lib/mimi/messaging/json_serializer.rb +45 -0
  29. data/lib/mimi/messaging/message.rb +25 -65
  30. data/lib/mimi/messaging/version.rb +3 -1
  31. data/mimi-messaging.gemspec +25 -23
  32. metadata +34 -77
  33. data/lib/mimi/messaging/connection.rb +0 -181
  34. data/lib/mimi/messaging/listener.rb +0 -72
  35. data/lib/mimi/messaging/mock.rb +0 -13
  36. data/lib/mimi/messaging/mock/connection.rb +0 -153
  37. data/lib/mimi/messaging/mock/request.rb +0 -18
  38. data/lib/mimi/messaging/mock/request_processor.rb +0 -92
  39. data/lib/mimi/messaging/model.rb +0 -27
  40. data/lib/mimi/messaging/model_provider.rb +0 -100
  41. data/lib/mimi/messaging/msgpack/msgpack_ext.rb +0 -14
  42. data/lib/mimi/messaging/msgpack/type_packer.rb +0 -104
  43. data/lib/mimi/messaging/notification.rb +0 -35
  44. data/lib/mimi/messaging/provider.rb +0 -48
  45. data/lib/mimi/messaging/request.rb +0 -56
  46. data/lib/mimi/messaging/request_processor.rb +0 -216
  47. data/lib/mimi/messaging/request_processor/context.rb +0 -39
  48. data/lib/mimi/messaging/request_processor/dsl.rb +0 -121
  49. data/lib/tasks/console_ext.rake +0 -6
  50. data/lib/tasks/console_helpers.rb +0 -116
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 839a61eb8dc38069954026c340bdbd6a530a8542
4
- data.tar.gz: faecf24ec54b10447d81b48ca1794438a6d3cf0c
3
+ metadata.gz: 54a536d257b3a394b605e80e1b24167e5912f785
4
+ data.tar.gz: 03374246a36903692068863563ec7a111cd18b8b
5
5
  SHA512:
6
- metadata.gz: b73ee235bc27d40cba7209e4049fd52f50ab8499a85243053bc12f3e7320d8730ad2072af3a91803354fa0472775ac857c21521b824fd62031d8bee7899363ba
7
- data.tar.gz: 958de3483a20f933c134b68c0061b632533db04993608f11f75b9b02093017c6e79bee89917b196d56931bb1b52aa8308afeb298474385565450d5ac45d6d099
6
+ metadata.gz: '0295bb31beb00e6370340e4db43bab2a145e9d463d514bcdf1eba944a171edb614133afc7384a9e1e3010b832c4ff4b547ae9a27e307efb19d4abe3acee0782d'
7
+ data.tar.gz: 5e3a7f512fc58d688551c9601c26b863872dfeafaf860554796f2493ba30234045c591520c453fa973cae529069516cc19653553cf369eca7f31bc7c5ac29395
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ .DS_Store
@@ -0,0 +1,66 @@
1
+ ---
2
+
3
+ require:
4
+ - rubocop-performance
5
+
6
+ AllCops:
7
+ Exclude:
8
+ - tmp/**/*
9
+
10
+ DisplayCopNames: true
11
+ DisplayStyleGuide: true
12
+
13
+ TargetRubyVersion: 2.5
14
+
15
+ Layout/ExtraSpacing:
16
+ AllowForAlignment: true
17
+
18
+ Lint/InterpolationCheck:
19
+ Enabled: false
20
+
21
+ Metrics:
22
+ Enabled: true
23
+
24
+ Metrics/LineLength:
25
+ Max: 100
26
+
27
+ Metrics/MethodLength:
28
+ Max: 25
29
+
30
+ Metrics/AbcSize:
31
+ Max: 25
32
+
33
+ Metrics/ModuleLength:
34
+ Max: 300
35
+
36
+ Naming/FileName:
37
+ Exclude:
38
+ - .simplecov
39
+
40
+ TrivialAccessors:
41
+ ExactNameMatch: true
42
+
43
+ Style/ModuleFunction:
44
+ EnforcedStyle: extend_self
45
+
46
+ # https://github.com/bbatsov/rubocop/pull/72
47
+ Style/AsciiComments:
48
+ Enabled: false
49
+
50
+ Style/StringLiterals:
51
+ EnforcedStyle: double_quotes
52
+
53
+ # Don't see why storing context information in the exception is a bad thing
54
+ Style/RaiseArgs:
55
+ Enabled: false
56
+
57
+ # Allow adding comments at `end` of classes and modules
58
+ Style/CommentedKeyword:
59
+ Enabled: false
60
+
61
+ # Allow `!!value` for casting to Boolean
62
+ Style/DoubleNegation:
63
+ Enabled: false
64
+
65
+ EmptyMethod:
66
+ EnforcedStyle: expanded
data/README.md CHANGED
@@ -1,8 +1,73 @@
1
- # mimi-messaging
1
+ # [WIP] mimi-messaging
2
2
 
3
- Communications via RabbitMQ for [mimi](https://github.com/kukushkin/mimi).
3
+ Interservice communication via message bus for microservices.
4
4
 
5
- [in development]
5
+ ## What
6
+
7
+ `mimi-messaging` is a Messaging layer -- an interservice
8
+ communication layer based on message bus, for connecting microservice applications.
9
+
10
+ * Command, Query, Event communication patterns
11
+ * "at-least-once" message delivery guarantees
12
+ * Abstract message bus interface, not bound to specific message broker implementation
13
+
14
+ See also: [Overview of Messaging layer properties](docs/Messaging_Layer_Properties.md)
15
+
16
+ ## Why
17
+
18
+ [Why HTTP is a bad choice for interservice communication?](docs/Why_HTTP_is_a_bad_choice.md)
19
+
20
+ TBD: Message bus pro's and con's.
21
+
22
+ ## How
23
+
24
+ Concepts:
25
+
26
+ * Command: one-to-one, send and forget
27
+ * Query: one-to-one, call and wait for response
28
+ * Event: one-to-many, broadcast
29
+
30
+ ## Setup
31
+
32
+ ```
33
+ gem "mimi-messaging", "~> 1.0"
34
+ gem "mimi-messaging-<ADAPTER>"
35
+ ```
36
+
37
+ ```
38
+ require "mimi/messaging"
39
+ require "mimi/messaging/<ADAPTER>"
40
+
41
+ Mimi::Messaging.use serializer: Mimi::Messaging::JsonSerializer
42
+ Mimi::Messaging.configure mq_adapter: "<ADAPTER>", ... # extra adapter specific options
43
+ Mimi::Messaging.start
44
+ ```
45
+
46
+ ## Usage
47
+
48
+ ```
49
+ response = Mimi::Messaging.query("orders/show", id: 123)
50
+ ```
51
+
52
+ ## Adapters
53
+
54
+ `mimi-messaging` is not bound to a specific message broker implementation like RabbitMQ or Kafka. It interacts with a message broker using an adapter interface and
55
+ there are several available adapters:
56
+
57
+ * [Kafka](https://github.com/kukushkin/mimi-messaging-kafka)
58
+ * RabbitMQ (TBD)
59
+ * NATS (TBD)
60
+ * Amazon SQS/SNS
61
+ * in-memory (single process)
62
+
63
+ ## Designing apps
64
+
65
+
66
+ There are only two hard problems in distributed systems:
67
+
68
+ 2. Exactly-once delivery
69
+ 1. Guaranteed order of messages
70
+ 2. Exactly-once delivery
6
71
 
7
72
 
8
73
  ## License
data/TODO.md ADDED
@@ -0,0 +1,8 @@
1
+ # TODO
2
+
3
+ * Terminology:
4
+ * what is target: for command, query, event
5
+ * what is target base: for command, query, event
6
+ * event or broadcast?
7
+ * Higher level processor: Command/QueryProcessor? EventProcessor
8
+ * Higher level message for producers: Mimi::Messaging::Message, Mimi::Messaging::Event ?
@@ -0,0 +1,141 @@
1
+ # Messaging Layer Properties
2
+
3
+ ## Communication Patterns
4
+
5
+ Messaging Layer provides an intersevice communucation layer based on abstracted
6
+ message bus, implementing the range of communication patterns:
7
+
8
+ * Command
9
+ * Query
10
+ * Event
11
+
12
+ ### Command
13
+
14
+ ![Command pattern diagram](./img/pattern--command.png)
15
+ * one-to-one, send and forget
16
+
17
+ *Command* is a communication pattern where application A (producer) asynchronously
18
+ sends a message to a queue, from which application B (consumer) receives the message.
19
+
20
+ In this case the application A sends the message and continues the execution immediately
21
+ after the message has been accepted by the Messaging Layer.
22
+
23
+ There can be multiple instances of application B running and processing messages from
24
+ the same queue. The Messaging Layer guarantees that only one instance of application B
25
+ will receive this message.
26
+
27
+ ### Query
28
+
29
+ ![Query pattern diagram](./img/pattern--query.png)
30
+ * one-to-one, request/response
31
+
32
+ *Query* is a communication pattern where application A sends a message (request) to
33
+ a queue, from which application B receives the message, and waits for another
34
+ message (response) from B.
35
+
36
+ In this case application A sends the message and stops execution until
37
+ the response from application B is received or the timeout is fired.
38
+
39
+ This communication pattern is synchronous, and there are several things that
40
+ may go wrong during this communication: the target queue name is wrong,
41
+ the application B may be down, or the application B just could not produce a response
42
+ in time and the timeout is fired.
43
+
44
+ There can be multiple instances of application B running and processing messages from
45
+ the same queue. The Messaging Layer guarantees that only one instance of application B
46
+ will receive this message, and the response message will be delivered to the same
47
+ instance of application A, that produced the request.
48
+
49
+
50
+ ### Event
51
+
52
+ ![Event pattern diagram](./img/pattern--event.png)
53
+ * one-to-many, pub/sub
54
+
55
+ *Event* is a communication pattern where application A sends a message (event) to
56
+ a topic, to which many other applications may subscribe and listen for events.
57
+ There can be multiple instances of the same application B subscribed to this topic,
58
+ or it may be different applications B and C subscribed to the same topic.
59
+
60
+ In this case the application A sends the message and continues the execution immediately
61
+ after the message has been accepted by the Messaging Layer. The Messaging Layer
62
+ delivers the message to the topic and all the subscribed listeners, if there are any.
63
+
64
+ #### Listening for events
65
+
66
+ While producing an event is simple and it only means posting a message to a topic,
67
+ listening for events has two variants:
68
+
69
+ ![Event directly diagram](./img/pattern--event-direct.png)
70
+ * Listening for events on a topic directly
71
+
72
+ An application can listen for events on a topic directly. That means that
73
+ whenever the event is published on a topic, every application instance listening for the
74
+ events directly will receive this event. If the application listening for the
75
+ events in such a way is down, it is not guaranteed that the events published while it
76
+ was offline will be delivered after it gets back online.
77
+
78
+ ![Event using a queue diagram](./img/pattern--event-using-queue.png)
79
+ * Listening for events on a topic using a queue
80
+
81
+ An application can listen for events on a topic using a bound queue. That means
82
+ that every event published on the given topic will be additionally put into specified
83
+ queue, from which the message is consumed by only one instance of the application.
84
+ In this case the queue will keep the messages (events) even while the listening
85
+ applications/instances are down, and the messages will be delivered once the
86
+ application gets back online.
87
+
88
+ ## Logical names for message targets
89
+
90
+ Whenever a message (command, query or event) is sent, Messaging Layer expects
91
+ a "target" for the message to be specified. This target is a logical name
92
+ that defines the destination of a message.
93
+
94
+ For commands and queries, the target of the message consists of a queue name
95
+ and a method name (e.g. `"customers/create"`).
96
+
97
+ For events, the target of the message consists of a topic name and an
98
+ event type (e.g. `"customers/created"`).
99
+
100
+ This allows to model the communication around your business domain concepts,
101
+ and not the implementation details like application or host names.
102
+
103
+ ## Delivery guarantee
104
+
105
+ Messaging Layer guarantees "at-least-once" message delivery.
106
+
107
+ Once the call to `command()`, `query()`, `event()` successfully completes,
108
+ it is guaranteed that the Messaging Layer accepted the message,
109
+ and the message will eventually be delivered to the recipient.
110
+
111
+ "at-least-once" means that in certain cases the same message may be delivered
112
+ more than once, and the applications consuming the messages must be prepared to
113
+ deal with it, which in most cases means implementing idempotent message processors.
114
+
115
+
116
+ ### Notes:
117
+
118
+ > `query()` method successfully returns only after the response has been received,
119
+ at which point the caller may be sure that not only the message has been accepted
120
+ by the Messaging Layer, but that it has been delivered and successfully processed
121
+ by the recepient.
122
+
123
+ > `event()` method successfully completing guarantees only that the message
124
+ will be delivered to the topic -- the message may still be lost by the listener if
125
+ it does not use a queue for keeping the messages
126
+
127
+
128
+ ## Load balancing
129
+
130
+ The Messaging Layer ensures best-effort load balancing of messages in case there
131
+ are multiple message processors for the same request target (for Command and Query
132
+ processors), or multiple listeners (for Event processors with a queue).
133
+
134
+
135
+ ## Ordering of messages
136
+
137
+ The Messaging Layer does NOT guarantee that the messages will be delivered
138
+ in the same order as they were produced.
139
+
140
+
141
+ --
@@ -0,0 +1,20 @@
1
+ # Why HTTP is a bad choice for interservice communication
2
+
3
+ [WIP]
4
+
5
+ Downsides of HTTP:
6
+ * inherently synchronous
7
+ * timeouts
8
+ * retries
9
+ * one-to-one, no pub/sub
10
+ * additional work required:
11
+ * network
12
+ * service discovery
13
+ * routing
14
+ * load balancing
15
+ * authentication/authorization
16
+
17
+
18
+ Pro's of HTTP:
19
+ * synchronous communication is simple
20
+ * HTTP as technology is well known by engineers
@@ -0,0 +1 @@
1
+ <mxfile modified="2019-07-14T14:14:39.587Z" host="www.draw.io" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36" etag="lgARSmjxxzsn12OMDTwz" version="10.9.6" type="google"><diagram id="y9hzfK7Ta8yHCBsTJmj-" name="Page-1">5Zbfk5owEMf/Gh7bASKoj4rae+lcp85Nbd8ysEqmgdAQT+hf32ASfuUc7c31rp0+mf2yu9l8dg04KMqqDxwX6UeWAHV8N6kctHJ833P9UP40Sq2UwA+UcOAk0U6dsCU/wURq9UgSKAeOgjEqSDEUY5bnEIuBhjlnp6HbntHhrgU+gCVsY0xt9QtJRKrUmTlWo98BOaRmZy+cqycZNs76JGWKE3bqSWjtoIgzJtQqqyKgDTzDRcVtLjxtC+OQi1sCZg+f774VafWQ4cX9fb5cpLB7p7M8YnrUB17oakVtEJxSImBb4LixT7LNDlqmIqPS8uQSl4UCvycVyL2We0JpxCjj53C02Wz8KJJ6KTj7DoMny2Dqyie6COACqoun81pmctiAZSB4LV1MgMFcj+xT17VAS2mvYUbDek4ObeYOpVxomr9B1rfILv9NshP0l5FFFtkfR5DLMV3OjnnScFs1JK6wthBO14tw7drQV5O1twleBq0/GaKd2WRb2q+CNrDQWlQhTxbNvSqtmOKyJPEQJFRE7Hrrrw3/94G2VpVux9mojZHL4nd9oxfVmF3Y2TJxqjhIrCt81AB5AHbkMVy/CAXmBxDXhs9u6I3/BQ4UC/I4LPepLuodPjEiD3LxkrMGQR1TR/XfBeNE01Eid5RIcbASyc7juudWNA7l5YLb17i5O9xgNKMqYzexLdPnD3H43w4xunGI/bccYjQPhjPhPXOIJ+EwUfhnZhjNX3SGpdl98yn37ssZrX8B</diagram></mxfile>
@@ -0,0 +1 @@
1
+ <mxfile modified="2019-07-14T14:29:20.445Z" host="www.draw.io" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36" etag="UPJeEwyjqKJsfKu6Yc1A" version="10.9.6" type="google"><diagram id="y9hzfK7Ta8yHCBsTJmj-" name="Page-1">7VhNc5swEP01HNtBYIh9xNhuLp10muk07U2FjdFUSIyQY9xfX8mIT9l1mniSNM0JdqWVdt8+iV0cP86rDwIX2UeeAnU8N60cf+F4HnK9UD20ZldrAi+oFWtBUjOpU1yTX9BYGu2GpFAOJkrOqSTFUJlwxiCRAx0Wgm+H0245He5a4DVYiusEU1v7laQyq7XTJiytvwSyzpqdUTirR3LcTDaRlBlO+ban8peOHwvOZf2WVzFQDV6DS223OjLaOiaAyfsYTL98vvxeZNWXHEdXV2weZXDzroH5DtONiTg27spdg8E2IxKuC5xoeavy7PjzTOZUSUi94rKokb8lFajN5reE0phTLvbm/mq18uJY6Usp+E8YjMyDC1eNGCdASKiOhoda0BTbgOcgxU5NMQYT34RiiNbivu3SFhhV1stYo8OGKOt25Q5L9WLg/AtoZxay89eBLJo8M7LIQjb6N5GdvTBgvddK2ekzA+tbwEpekMQCV/ANSzVsCw3ECagtBC+WUbh0bcwXkyVaBedB1nNPcxZ5T4ltYGFrwQosjXQtoKSE4rJUyA+QhIrIm977N52A94GRFpXJx17YNQJTzt/0hZ6VFjuzvdTY1c5BapUdowyoAPhGJHD6HpRYrEGeYp+d0XseBgEUS3I3dPdQFs0OnzhRgbSEmQ754nsjHtRRGqN++TJaB42/7xejhWoYrIVU4vGuN63QE0qLdS0uDydi+N8S0b8nEb3nJKI/C4Y3F3ogEyfhcKHwsUQ85u/opnWDEWvrFc/KYWSXAG8kPlDXv5DbdOKe6Tb1x5/nc5F45DAKn4LEdrn1RuJDff8bix/GYm/yFCy2C9tIs2Lzg5Iyg1JT5g72bnKmg9F5P9hVqGpf/ql1YJzBqGswKkzJmukjovYBpZ/r3oEkmEZmICdpqrc52KsMuxnn8c0HQkc+4f3mAx3g7bjoPN+vCLvoU0nZ+4yLgiqoJKmzw1K9FislZgojfYQSUCdIp1Fm0CXzteauvTuOt+Roep7UKbH7rVofx+7ntL/8DQ==</diagram></mxfile>
@@ -0,0 +1 @@
1
+ <mxfile modified="2019-07-14T14:31:44.611Z" host="www.draw.io" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36" etag="knmCqr-WVQHLlz4MjdX8" version="10.9.6" type="google"><diagram id="y9hzfK7Ta8yHCBsTJmj-" name="Page-1">5VnLctowFP0alu34DSx5JtOZJm2YTGl3ii2wprLlygJMv76SLYMtOUATNwG6snT1Puf43iu7Y4+i7IaCJPxMAog7lhFkHXvcsSzTsDz+EJZtYXEttzAsKQpkp71hhn7DcqS0rlAA01pHRghmKKkbfRLH0Gc1G6CUbOrdFgTXV03AEmqGmQ+wbv2GAhYW1l55LGG/hWgZliubXr9oiUDZWZ4kDUFANhWTPenYI0oIK0pRNoJYgFfiUoybPtO62xiFMTtlQO/x4fZHEmaPERjc38fDQQjnH0qY1wCv5IlHcrtsW2KwCRGDswT4or7hPHfsYcgizGsmL4I0KZBfoAzyxYYLhPGIYELz4fZ0OrVGI25PGSU/Ya1l6HYN3qKfRR5vDSmDWcUkz3YDSQQZ3fIustXty6NIoe1w3+xpc6UprDBW2oAUynI38x5LXpBw/gW0fQ3Z4XUgazrvjKypITu4TGTPDVjrWiXbe2dgbQ1YRhLka+BSsooDAdtYAHEEag3B7mTgTQwd87EzMaduO8haxnHNmtZbYutq2GqwwjgYiFyA13wM0pQjX0MSZojNK+XvgoCPrqyNM8lHXtmWlZhvfl6tVEaJ6n5YXivHPctBSlbUh8fdHgN0CdlxscGgltnojJ74MlCIAUPrej7UxKJc4QtB/GQ7wfTqerEtRQfFseWgavqizGPaSnzvKhMVuGgTceLBttItER1STXU7XF4uRO9/EaKtC3HmxRPM/Dv6tb+IvDv8CT8YZTg5EyHafbfuucwXKtHx6hN5rxXiM/v1mj3tXrXFjK1q2NQj1eWLuFGcp3rTUiVnomLFnTpGS+7UVuNzSyp2XcVtO26rKj7EbUXEv1aQFy1Dv9yef8plqzdbQ0+5+g2Kc1rIuA759QZ49evC5cFrNnw4eFN4r9EFvyqPMM/KAytysVUdnOyBHeW17v+jPEL1wFa7eUQjZc4VaviQLzyaRpxXLnxpGnaVdUzjDbII/cPCQIhk9YRRGsJUsLmG+S5JLM4iZND4VYcHInYo0MUkhkqMkyaA0TIWLwhfB3L7UIQ15AM8kA0RCgKxTGNkrcfeFkLlLjSqV6jqxx+zQbbqpb+1WKnfuUtOUJqTlRdjRvjjScDBn3mykl4vS+odoXxZ3o+lrsYSifE2f3Fgzk/KQOyLIlkUWSR3cD7k/k2QyELREsE0Ff/qLGNBSbQzy8zzWrl0DK/GZbenU9lrh0pe3f+MLHzo/peuPfkD</diagram></mxfile>
@@ -0,0 +1 @@
1
+ <mxfile modified="2019-07-14T14:31:23.619Z" host="www.draw.io" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36" etag="mj5YSntAqhnDTmg4xXPi" version="10.9.6" type="google"><diagram id="y9hzfK7Ta8yHCBsTJmj-" name="Page-1">7VnLdpswEP0aL9sDEs+ljR/ZtOlpmtbJTgcUwwkgKuQY9+srgjAg+ZEmxE7irqwZvZg716OLGEAvKWYUZeEXEuB4ALSgGMDxAABdAxb/KT3rymMCs3IsaBSIQY3jKvqD65nCu4wCnHcGMkJiFmVdp0/SFPus40OUklV32B2Ju7tmaIEVx5WPYtX7KwpYWHmdOqzSf4GjRVjvrFtu1ZOgerCIJA9RQFYtF5wMoEcJYVUrKTwcl+DVuFTzpjt6Nw9GccqeMsG5/n5xm4XFdYKGl5fpaBji+aca5gcUL0XEI/G4bF1jsAojhq8y5Jf2iud5AEchS2Ju6byJ8qxC/i4qMN9sdBfFsUdiQh+nw+l0CjyP+3NGyT3u9IxMW+M9aiwivAdMGS5aLhHbDJMEM7rmQ0SvAUUogmhAE/aqSZspXGErY7UPCaIsNis3WPKGgPMfoHU/KrK6cWJkdQXZ4ftE1pGANU8MLPiolHVODCxUgGUki3wFXEqWaVDCNi6BOAC1gqA9GVoTTcV8bEz0qdkPspuyuoezOjgmtqaCrQIrToNhqQW45ccozznyHSRxEbF5q31TJuCzKaxxIfLxaKxrI+UPP28brVml2Ux7tOp5O3OQkyX18eGyxxBdYHaYbDjoKBs1o0/8M1AcIxY9dPXQtiyKHb6RiEe2q8ZBIPGgCltMassXaR1dPt9taaEKF2Uhnni0bg3LygH57ufVbYngtilRtFqxIewG0udz2DoXDsMnchi8KQ5D1+xyQn8miQ2ru5D1OhyGrsRh7Qgc1lVZ5r1P9WBKZxw4tS7TVWF25vXBfVP1QTrjDK2nMw7KjOqrPsgvHtYx6oMqgs+cxPUp8p/FvbAYgGOw2DhjFoOvq+zn7P4HAWPHSeybWTEf168lH4zEmwvoXe8tfZHYkEjsdm5xX0zifSlrcfj3EvOmTOSjXEcoumwLXXdKNWg5XfhsVaq5W9hm9CDVtkKrKrXTieAXISuLYKgfTwRvRfZdygepKh6sxPv+rof1xJuqvLAv+eC8TuU1ZPnwsosebjbf8qrhzRdROPkL</diagram></mxfile>
@@ -0,0 +1 @@
1
+ <mxfile modified="2019-07-14T14:14:30.733Z" host="www.draw.io" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36" etag="VIpIcM9pChy9e7uzRAZn" version="10.9.6" type="google"><diagram id="y9hzfK7Ta8yHCBsTJmj-" name="Page-1">5VdNc5swEP01HJsBZLBzNDZ2Lp106sk07U0BGTQRiAoR4/z6SkYYhOzE8cQdd+qLtU+7+nj7kFYWmGX1ksEi/UpjRCzXjmsLzC3XdWzXF38S2TaI53oNkDAcK6cOWOFX1EYqtMIxKjVHTinhuNDBiOY5iriGQcboRndbU6LPWsAEGcAqgsREf+CYpw06abcl8TuEk7Sd2fFvm54Mts5qJ2UKY7rpQSC0wIxRyptWVs8QkeS1vDRxiyO9+4UxlPNTAiYP3+9+FWn9kMHp/X0eTFP0+EWN8gJJpTY8Vavl25aCTYo5WhUwkvZGpNkCQcozIixHNGFZNMSvcY3EXMEaEzKjhLJdOFgsFu5sJvCSM/qMtJ7AG9uix9xKuy7EOKp7kNraEtEMcbYVLm1vS/N2YG+6rHkKSnsJazGodJLsR+6oFA3F5geYdQ1mg3+T2RG4MmaBwezvConmkF1GqzyWvM0lE+9wbVA4Dqd+aJukz0ehs/A+h1p3pFM7MZnds/1XqPUMag1WUR5P5bkqrIjAssSRTiSqMX/stX9K/m88Zc1rlY6dsW2NXCz+sW/0oqTZhe2sNu5oCkpasQi9f+5xyBLE39cairVbwkzoid8CQwRy/KLfLYeyqGb4RrHY2dFDzhBCs28V1b8LhgONBwPZg4EaYoyBRObhtudWSIfy+IL313h7dtjeQKPNiJ1i95yeL2L/fxExOFHE7lWJGNx6uiacM0U88vWB/MtoGNxeVsN3i3n+EPoAb5YurtgSVqvwwB13toZtTcPjE0Xs6CIeX07F7okqdq5LxYOjGJyrYjA8ik+U8WcpbWQojaGyoHlpFlSiquG6xoQrfoVPOwepAvUtCW8vsLy5rGEJTnIpUaELJEqoQFZHWLyvpqojw3Es4wMCnxAJYPSc7Aq3Xsm13v0OiuzNj2dYh+1fiWrFVv8hdqg+s29sMPE+RS+Do0oPp+t1iT6YXWF2b8fGvXuBg/AP</diagram></mxfile>
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Base class for an event listener with DSL magic
4
+ #
5
+ # Usage:
6
+ # class HelloListener < BasicEventListener
7
+ # topic "hello", using_queue: "listener.hello"
8
+ #
9
+ # def world
10
+ # puts "hello/world event received: #{message}"
11
+ # end
12
+ # end
13
+ #
14
+ class BasicEventListener
15
+ attr_reader :message
16
+
17
+ def initialize(message, _opts = {})
18
+ @message = message
19
+ end
20
+
21
+ def self.call_event(method_name, message, opts)
22
+ new(message, opts).send(method_name.to_sym)
23
+ end
24
+
25
+ # Subclass exposes itself by declaring the event topic that it is going to listen for,
26
+ # and an optional :using_queue parameter.
27
+ #
28
+ def self.topic(topic_name, params = {})
29
+ if params[:using_queue]
30
+ Mimi::Messaging.register_event_processor_with_queue(topic_name, params[:using_queue], self)
31
+ else
32
+ Mimi::Messaging.register_event_processor(topic_name, params[:using_queue], self)
33
+ end
34
+ end
35
+ end # class BasicEventListener
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Base class for a request (command and query) processor with DSL magic.
4
+ #
5
+ # Usage:
6
+ # class HelloProcessor < BasicRequestProcessor
7
+ # queue "hello"
8
+ #
9
+ # def world
10
+ # puts "hello/world called with the message: #{message}"
11
+ # end
12
+ # end
13
+ #
14
+ #
15
+ class BasicRequestProcessor
16
+ attr_reader :message
17
+
18
+ def initialize(message, _opts = {})
19
+ @message = message
20
+ end
21
+
22
+ def self.call_command(method_name, message, opts)
23
+ new(message, opts).send(method_name.to_sym)
24
+ end
25
+
26
+ def self.call_query(method_name, message, opts)
27
+ result = new(message, opts).send(method_name.to_sym)
28
+ return result if result.is_a?(Hash)
29
+
30
+ raise "#{name}##{method_name}() is expected to return a Hash, but returned #{result.class}"
31
+ end
32
+
33
+ # Subclass exposes itself by declaring the queue that is used to accept requests
34
+ #
35
+ def self.queue(queue_name)
36
+ Mimi::Messaging.register_request_processor(queue_name, self)
37
+ end
38
+ end # class BasicRequestProcessor
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Using Mimi::Messaging lower-level abstraction,
5
+ # without using the adapter directly
6
+ #
7
+
8
+ require "mimi/messaging"
9
+ require "logger"
10
+ require_relative "basic_request_processor"
11
+ require_relative "basic_event_listener"
12
+
13
+ #
14
+ # An example request processor class
15
+ #
16
+ class HelloProcessor < BasicRequestProcessor
17
+ queue "hello"
18
+
19
+ def world
20
+ puts "hello/world request received: #{message}"
21
+ { a: 1 }
22
+ end
23
+
24
+ def command
25
+ puts "hello/command request received: #{message}"
26
+ end
27
+ end # class HelloProcessor
28
+
29
+ #
30
+ # An example event listener class
31
+ #
32
+ class HelloListener < BasicEventListener
33
+ topic "hello", using_queue: "listener.hello"
34
+
35
+ def world
36
+ puts "hello/world event received: #{message}"
37
+ end
38
+ end # class HelloListener
39
+
40
+ #
41
+ Mimi::Messaging.use(
42
+ serializer: Mimi::Messaging::JsonSerializer,
43
+ logger: Logger.new(STDOUT)
44
+ )
45
+ Mimi::Messaging.configure(mq_adapter: :memory)
46
+ Mimi::Messaging.start
47
+
48
+ result = Mimi::Messaging.command("hello/world", a: 123)
49
+ puts "Response: #{result}"
50
+ puts
51
+
52
+ result = Mimi::Messaging.query("hello/world", b: 456)
53
+ puts "Response: #{result}"
54
+ puts
55
+
56
+ Mimi::Messaging.event("hello/world", c: 789)
57
+ puts
58
+
59
+ Mimi::Messaging.stop