outboxer 0.1.0 → 0.1.2
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.
- checksums.yaml +4 -4
- data/README.md +50 -22
- data/doc/Outboxer/Models/Exception.html +124 -0
- data/doc/Outboxer/Models/Message.html +144 -0
- data/doc/Outboxer/Models/Outboxable/ClassMethods.html +105 -0
- data/doc/Outboxer/Models/Outboxable.html +265 -0
- data/doc/Outboxer/Models.html +119 -0
- data/doc/Outboxer/Publisher/Args.html +310 -0
- data/doc/Outboxer/Publisher.html +384 -0
- data/doc/Outboxer/Railtie.html +124 -0
- data/doc/Outboxer.html +150 -0
- data/doc/_index.html +211 -0
- data/doc/class_list.html +51 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +58 -0
- data/doc/css/style.css +497 -0
- data/doc/file.README.html +180 -0
- data/doc/file_list.html +56 -0
- data/doc/frames.html +17 -0
- data/doc/index.html +180 -0
- data/doc/js/app.js +314 -0
- data/doc/js/full_list.js +216 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +99 -0
- data/doc/top-level-namespace.html +110 -0
- data/generators/outboxer/templates/bin/publisher.rb +8 -1
- data/lib/outboxer/models/message.rb +2 -1
- data/lib/outboxer/publisher.rb +19 -0
- data/lib/outboxer/version.rb +1 -1
- data/lib/outboxer.rb +2 -0
- data/outboxer.gemspec +1 -1
- metadata +25 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99b8c36fa2db36b780ca732a63aba4df7f38ccd06d7a2403961a2cb483085153
|
4
|
+
data.tar.gz: 33db69284cdbc1fbf8398c98799deabd2a09b38eb863df2e2f88943db2bfa25d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5191c2ba363decec6729efd72dbaadd697241f74c11f07dfd722874fdc6df8be0b5001e696159f0ba17e2c744447dc11c256f90af17edb6bb03c68452e237c31
|
7
|
+
data.tar.gz: fdd2cfaecfa7d2972566ef340a164992325a1c08cc5810c7eee20a4218901082fb2ce45dcd10cb66ecd3747ffc55b5a3f135cb8a0acb7fb80a74f2c4d9e012c0
|
data/README.md
CHANGED
@@ -1,10 +1,23 @@
|
|
1
1
|
# Outboxer
|
2
2
|
|
3
|
-
|
3
|
+
## Background
|
4
4
|
|
5
|
-
|
5
|
+
Typically in event driven Ruby on Rails applications:
|
6
6
|
|
7
|
-
|
7
|
+
1. a domain event model is created in an SQL database table
|
8
|
+
2. a sidekiq worker is queued to handle the domain event asynchronously
|
9
|
+
|
10
|
+
## Problem
|
11
|
+
|
12
|
+
As these two operations span multiple database types (SQL and redis), they can not be combined into a single atomic operation using a transaction. If either step fails, inconsistencies can occur.
|
13
|
+
|
14
|
+
## Solution
|
15
|
+
|
16
|
+
Outboxer is a simple Ruby on Rails implementation of the [transactional outbox pattern](https://microservices.io/patterns/data/transactional-outbox.html): a well established solution to this problem. It ensures both operations succeed _eventually_, or both fail.
|
17
|
+
|
18
|
+
### Getting started
|
19
|
+
|
20
|
+
### Installation
|
8
21
|
|
9
22
|
1. Add the Outboxer gem to your application's Gemfile:
|
10
23
|
|
@@ -24,18 +37,9 @@ bundle install
|
|
24
37
|
bin/rails generate outboxer:install
|
25
38
|
```
|
26
39
|
|
27
|
-
|
28
|
-
|
29
|
-
### 1. Migrate your database
|
30
|
-
|
31
|
-
```bash
|
32
|
-
bin/rake db:migrate
|
33
|
-
```
|
34
|
-
|
35
|
-
|
36
|
-
### 2. Include Outboxer into existing model
|
40
|
+
### Usage
|
37
41
|
|
38
|
-
|
42
|
+
#### 1. Include `Outboxer::Outboxable` into your existing Message model
|
39
43
|
|
40
44
|
```ruby
|
41
45
|
class Message < ApplicationRecord
|
@@ -43,26 +47,50 @@ class Message < ApplicationRecord
|
|
43
47
|
end
|
44
48
|
```
|
45
49
|
|
46
|
-
|
50
|
+
#### 2. Update the generated bin/publish block e.g.
|
47
51
|
|
48
|
-
|
52
|
+
```ruby
|
53
|
+
Outboxer::Publisher.publish do |args|
|
54
|
+
args.logger.info("[#{message.id}] publishing")
|
49
55
|
|
50
|
-
|
56
|
+
Worker.perform_async({ message_id: args.message.id })
|
51
57
|
|
52
|
-
|
53
|
-
Outboxer::Publisher.publish do |message:, logger:|
|
54
|
-
Worker.perform_async({ message_id: message.id })
|
58
|
+
args.logger.info("[#{message.id}] published")
|
55
59
|
end
|
56
60
|
```
|
57
61
|
|
58
|
-
|
62
|
+
#### 3. Migrate the database
|
59
63
|
|
60
|
-
|
64
|
+
```bash
|
65
|
+
bin/rake db:migrate
|
66
|
+
```
|
67
|
+
|
68
|
+
#### 4. Run the publisher
|
61
69
|
|
62
70
|
```bash
|
63
71
|
bin/publisher
|
64
72
|
```
|
65
73
|
|
74
|
+
## Implementation
|
75
|
+
|
76
|
+
1. when an `ActiveRecord` model that includes `Outbox::Outboxable` is created, an `unpublished` `Outboxer::Message` is automatically created in the same transaction, with `Outboxer::Message#message` polymorphically assigned to the original model
|
77
|
+
|
78
|
+
2. When the publisher finds a new `unpublished` `Outboxer::Message`, it yields to a user-supplied block and then:
|
79
|
+
- removes it if the task completes successfully
|
80
|
+
- marks it as failed and records the error if there's a problem
|
81
|
+
|
82
|
+
To see all the parts working together in a single place, check out the [publisher_spec.rb](https://github.com/fast-programmer/outboxer/blob/master/spec/outboxer/publisher_spec.rb)
|
83
|
+
|
84
|
+
|
85
|
+
## Motivation
|
86
|
+
|
87
|
+
Outboxer was created with 4 key benefits in mind:
|
88
|
+
|
89
|
+
1. speed of integration into existing Ruby on Rails applications (< 1 hour)
|
90
|
+
2. comprehensive documentation that is easy to understand
|
91
|
+
3. high reliability in production environments (100% code coverage)
|
92
|
+
4. forever free to use in commerical applications (MIT licence)
|
93
|
+
|
66
94
|
## Contributing
|
67
95
|
|
68
96
|
Bug reports and pull requests are welcome on GitHub at https://github.com/fast-programmer/outboxer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/fast-programmer/outboxer/blob/main/CODE_OF_CONDUCT.md).
|
@@ -0,0 +1,124 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>
|
7
|
+
Class: Outboxer::Models::Exception
|
8
|
+
|
9
|
+
— Documentation by YARD 0.9.34
|
10
|
+
|
11
|
+
</title>
|
12
|
+
|
13
|
+
<link rel="stylesheet" href="../../css/style.css" type="text/css" />
|
14
|
+
|
15
|
+
<link rel="stylesheet" href="../../css/common.css" type="text/css" />
|
16
|
+
|
17
|
+
<script type="text/javascript">
|
18
|
+
pathId = "Outboxer::Models::Exception";
|
19
|
+
relpath = '../../';
|
20
|
+
</script>
|
21
|
+
|
22
|
+
|
23
|
+
<script type="text/javascript" charset="utf-8" src="../../js/jquery.js"></script>
|
24
|
+
|
25
|
+
<script type="text/javascript" charset="utf-8" src="../../js/app.js"></script>
|
26
|
+
|
27
|
+
|
28
|
+
</head>
|
29
|
+
<body>
|
30
|
+
<div class="nav_wrap">
|
31
|
+
<iframe id="nav" src="../../class_list.html?1"></iframe>
|
32
|
+
<div id="resizer"></div>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div id="main" tabindex="-1">
|
36
|
+
<div id="header">
|
37
|
+
<div id="menu">
|
38
|
+
|
39
|
+
<a href="../../_index.html">Index (E)</a> »
|
40
|
+
<span class='title'><span class='object_link'><a href="../../Outboxer.html" title="Outboxer (module)">Outboxer</a></span></span> » <span class='title'><span class='object_link'><a href="../Models.html" title="Outboxer::Models (module)">Models</a></span></span>
|
41
|
+
»
|
42
|
+
<span class="title">Exception</span>
|
43
|
+
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<div id="search">
|
47
|
+
|
48
|
+
<a class="full_list_link" id="class_list_link"
|
49
|
+
href="../../class_list.html">
|
50
|
+
|
51
|
+
<svg width="24" height="24">
|
52
|
+
<rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
|
53
|
+
<rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
|
54
|
+
<rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
|
55
|
+
</svg>
|
56
|
+
</a>
|
57
|
+
|
58
|
+
</div>
|
59
|
+
<div class="clear"></div>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<div id="content"><h1>Class: Outboxer::Models::Exception
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
</h1>
|
67
|
+
<div class="box_info">
|
68
|
+
|
69
|
+
<dl>
|
70
|
+
<dt>Inherits:</dt>
|
71
|
+
<dd>
|
72
|
+
<span class="inheritName">ActiveRecord::Base</span>
|
73
|
+
|
74
|
+
<ul class="fullTree">
|
75
|
+
<li>Object</li>
|
76
|
+
|
77
|
+
<li class="next">ActiveRecord::Base</li>
|
78
|
+
|
79
|
+
<li class="next">Outboxer::Models::Exception</li>
|
80
|
+
|
81
|
+
</ul>
|
82
|
+
<a href="#" class="inheritanceTree">show all</a>
|
83
|
+
|
84
|
+
</dd>
|
85
|
+
</dl>
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
<dl>
|
98
|
+
<dt>Defined in:</dt>
|
99
|
+
<dd>lib/outboxer/models/exception.rb</dd>
|
100
|
+
</dl>
|
101
|
+
|
102
|
+
</div>
|
103
|
+
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
|
113
|
+
|
114
|
+
</div>
|
115
|
+
|
116
|
+
<div id="footer">
|
117
|
+
Generated on Sat Aug 5 04:37:46 2023 by
|
118
|
+
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
119
|
+
0.9.34 (ruby-2.7.8).
|
120
|
+
</div>
|
121
|
+
|
122
|
+
</div>
|
123
|
+
</body>
|
124
|
+
</html>
|
@@ -0,0 +1,144 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>
|
7
|
+
Class: Outboxer::Models::Message
|
8
|
+
|
9
|
+
— Documentation by YARD 0.9.34
|
10
|
+
|
11
|
+
</title>
|
12
|
+
|
13
|
+
<link rel="stylesheet" href="../../css/style.css" type="text/css" />
|
14
|
+
|
15
|
+
<link rel="stylesheet" href="../../css/common.css" type="text/css" />
|
16
|
+
|
17
|
+
<script type="text/javascript">
|
18
|
+
pathId = "Outboxer::Models::Message";
|
19
|
+
relpath = '../../';
|
20
|
+
</script>
|
21
|
+
|
22
|
+
|
23
|
+
<script type="text/javascript" charset="utf-8" src="../../js/jquery.js"></script>
|
24
|
+
|
25
|
+
<script type="text/javascript" charset="utf-8" src="../../js/app.js"></script>
|
26
|
+
|
27
|
+
|
28
|
+
</head>
|
29
|
+
<body>
|
30
|
+
<div class="nav_wrap">
|
31
|
+
<iframe id="nav" src="../../class_list.html?1"></iframe>
|
32
|
+
<div id="resizer"></div>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div id="main" tabindex="-1">
|
36
|
+
<div id="header">
|
37
|
+
<div id="menu">
|
38
|
+
|
39
|
+
<a href="../../_index.html">Index (M)</a> »
|
40
|
+
<span class='title'><span class='object_link'><a href="../../Outboxer.html" title="Outboxer (module)">Outboxer</a></span></span> » <span class='title'><span class='object_link'><a href="../Models.html" title="Outboxer::Models (module)">Models</a></span></span>
|
41
|
+
»
|
42
|
+
<span class="title">Message</span>
|
43
|
+
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<div id="search">
|
47
|
+
|
48
|
+
<a class="full_list_link" id="class_list_link"
|
49
|
+
href="../../class_list.html">
|
50
|
+
|
51
|
+
<svg width="24" height="24">
|
52
|
+
<rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
|
53
|
+
<rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
|
54
|
+
<rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
|
55
|
+
</svg>
|
56
|
+
</a>
|
57
|
+
|
58
|
+
</div>
|
59
|
+
<div class="clear"></div>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<div id="content"><h1>Class: Outboxer::Models::Message
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
</h1>
|
67
|
+
<div class="box_info">
|
68
|
+
|
69
|
+
<dl>
|
70
|
+
<dt>Inherits:</dt>
|
71
|
+
<dd>
|
72
|
+
<span class="inheritName">ActiveRecord::Base</span>
|
73
|
+
|
74
|
+
<ul class="fullTree">
|
75
|
+
<li>Object</li>
|
76
|
+
|
77
|
+
<li class="next">ActiveRecord::Base</li>
|
78
|
+
|
79
|
+
<li class="next">Outboxer::Models::Message</li>
|
80
|
+
|
81
|
+
</ul>
|
82
|
+
<a href="#" class="inheritanceTree">show all</a>
|
83
|
+
|
84
|
+
</dd>
|
85
|
+
</dl>
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
<dl>
|
98
|
+
<dt>Defined in:</dt>
|
99
|
+
<dd>lib/outboxer/models/message.rb</dd>
|
100
|
+
</dl>
|
101
|
+
|
102
|
+
</div>
|
103
|
+
|
104
|
+
|
105
|
+
|
106
|
+
<h2>
|
107
|
+
Constant Summary
|
108
|
+
<small><a href="#" class="constants_summary_toggle">collapse</a></small>
|
109
|
+
</h2>
|
110
|
+
|
111
|
+
<dl class="constants">
|
112
|
+
|
113
|
+
<dt id="STATUS-constant" class="">STATUS =
|
114
|
+
|
115
|
+
</dt>
|
116
|
+
<dd><pre class="code"><span class='lbrace'>{</span>
|
117
|
+
<span class='label'>unpublished:</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>unpublished</span><span class='tstring_end'>"</span></span><span class='comma'>,</span>
|
118
|
+
<span class='label'>publishing:</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>publishing</span><span class='tstring_end'>"</span></span><span class='comma'>,</span>
|
119
|
+
<span class='label'>failed:</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>failed</span><span class='tstring_end'>"</span></span>
|
120
|
+
<span class='rbrace'>}</span><span class='period'>.</span><span class='id identifier rubyid_freeze'>freeze</span></pre></dd>
|
121
|
+
|
122
|
+
</dl>
|
123
|
+
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
|
132
|
+
|
133
|
+
|
134
|
+
</div>
|
135
|
+
|
136
|
+
<div id="footer">
|
137
|
+
Generated on Sat Aug 5 04:37:46 2023 by
|
138
|
+
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
139
|
+
0.9.34 (ruby-2.7.8).
|
140
|
+
</div>
|
141
|
+
|
142
|
+
</div>
|
143
|
+
</body>
|
144
|
+
</html>
|
@@ -0,0 +1,105 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>
|
7
|
+
Module: Outboxer::Models::Outboxable::ClassMethods
|
8
|
+
|
9
|
+
— Documentation by YARD 0.9.34
|
10
|
+
|
11
|
+
</title>
|
12
|
+
|
13
|
+
<link rel="stylesheet" href="../../../css/style.css" type="text/css" />
|
14
|
+
|
15
|
+
<link rel="stylesheet" href="../../../css/common.css" type="text/css" />
|
16
|
+
|
17
|
+
<script type="text/javascript">
|
18
|
+
pathId = "Outboxer::Models::Outboxable::ClassMethods";
|
19
|
+
relpath = '../../../';
|
20
|
+
</script>
|
21
|
+
|
22
|
+
|
23
|
+
<script type="text/javascript" charset="utf-8" src="../../../js/jquery.js"></script>
|
24
|
+
|
25
|
+
<script type="text/javascript" charset="utf-8" src="../../../js/app.js"></script>
|
26
|
+
|
27
|
+
|
28
|
+
</head>
|
29
|
+
<body>
|
30
|
+
<div class="nav_wrap">
|
31
|
+
<iframe id="nav" src="../../../class_list.html?1"></iframe>
|
32
|
+
<div id="resizer"></div>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div id="main" tabindex="-1">
|
36
|
+
<div id="header">
|
37
|
+
<div id="menu">
|
38
|
+
|
39
|
+
<a href="../../../_index.html">Index (C)</a> »
|
40
|
+
<span class='title'><span class='object_link'><a href="../../../Outboxer.html" title="Outboxer (module)">Outboxer</a></span></span> » <span class='title'><span class='object_link'><a href="../../Models.html" title="Outboxer::Models (module)">Models</a></span></span> » <span class='title'><span class='object_link'><a href="../Outboxable.html" title="Outboxer::Models::Outboxable (module)">Outboxable</a></span></span>
|
41
|
+
»
|
42
|
+
<span class="title">ClassMethods</span>
|
43
|
+
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<div id="search">
|
47
|
+
|
48
|
+
<a class="full_list_link" id="class_list_link"
|
49
|
+
href="../../../class_list.html">
|
50
|
+
|
51
|
+
<svg width="24" height="24">
|
52
|
+
<rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
|
53
|
+
<rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
|
54
|
+
<rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
|
55
|
+
</svg>
|
56
|
+
</a>
|
57
|
+
|
58
|
+
</div>
|
59
|
+
<div class="clear"></div>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<div id="content"><h1>Module: Outboxer::Models::Outboxable::ClassMethods
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
</h1>
|
67
|
+
<div class="box_info">
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
<dl>
|
80
|
+
<dt>Defined in:</dt>
|
81
|
+
<dd>lib/outboxer/models/outboxable.rb</dd>
|
82
|
+
</dl>
|
83
|
+
|
84
|
+
</div>
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
</div>
|
96
|
+
|
97
|
+
<div id="footer">
|
98
|
+
Generated on Sat Aug 5 04:37:46 2023 by
|
99
|
+
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
100
|
+
0.9.34 (ruby-2.7.8).
|
101
|
+
</div>
|
102
|
+
|
103
|
+
</div>
|
104
|
+
</body>
|
105
|
+
</html>
|