mimi-messaging 0.1.12 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +428 -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/version.rb +3 -1
  30. data/mimi-messaging.gemspec +25 -23
  31. metadata +34 -78
  32. data/lib/mimi/messaging/connection.rb +0 -182
  33. data/lib/mimi/messaging/listener.rb +0 -72
  34. data/lib/mimi/messaging/message.rb +0 -74
  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 -19
  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: 828625be9415bb194ed21f492e906c9907b449c3
4
- data.tar.gz: 5753eaf082cf97ffeaf4fc4482c67c28d6f51678
3
+ metadata.gz: 81b174d0230b57feade2b45ddf7ba624bcaae33e
4
+ data.tar.gz: 810f82256c0e7b94e7c6f5df9b2f66b87bd640fb
5
5
  SHA512:
6
- metadata.gz: 968baad2e92dfcf9a90f5bce591a4f04c8c246f6e276ee495668680bc091b0d8db6c4cc806aab7cf0cb0e34355d9626c22d6690b8e544bb2364f0424f01b3bab
7
- data.tar.gz: c3ebd575f807888a2dbd81b12e3eb43a756392f2f2da9c8cd979a3370efa3422d1c3a650129fcc9a9543be6e53225d047ab9fca2cff27f0f6dc8bf23f89feff7
6
+ metadata.gz: 326f345bb63e01400930c1127f2fecc27769bc3c3ce43e04c96abedcafc054c74b25c459acc1079a6e20249dd1b3614c67d8410be9e0b0e05dd77beb7f57aef2
7
+ data.tar.gz: 124ad7375b0465e09cbe7b23c184ff484572d0bab3f4f85e6c4da9750026d2b7ae62ff03d2078a2ece20d6d3ff8e0e7fc1b91d95a16c1fe118adbd420e336ae4
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ .DS_Store
data/.rubocop.yml ADDED
@@ -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>
Binary file
Binary file
Binary file
Binary file
@@ -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