table_sync 4.2.1 → 6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +52 -0
  3. data/CHANGELOG.md +75 -9
  4. data/Gemfile.lock +159 -152
  5. data/README.md +4 -1
  6. data/docs/message_protocol.md +3 -3
  7. data/docs/publishing/configuration.md +143 -0
  8. data/docs/publishing/manual.md +155 -0
  9. data/docs/publishing/publishers.md +162 -0
  10. data/docs/publishing.md +35 -119
  11. data/docs/receiving.md +11 -6
  12. data/lib/table_sync/errors.rb +31 -22
  13. data/lib/table_sync/event.rb +35 -0
  14. data/lib/table_sync/orm_adapter/active_record.rb +25 -0
  15. data/lib/table_sync/orm_adapter/base.rb +92 -0
  16. data/lib/table_sync/orm_adapter/sequel.rb +29 -0
  17. data/lib/table_sync/publishing/batch.rb +53 -0
  18. data/lib/table_sync/publishing/data/objects.rb +50 -0
  19. data/lib/table_sync/publishing/data/raw.rb +27 -0
  20. data/lib/table_sync/publishing/helpers/attributes.rb +63 -0
  21. data/lib/table_sync/publishing/helpers/debounce.rb +134 -0
  22. data/lib/table_sync/publishing/helpers/objects.rb +39 -0
  23. data/lib/table_sync/publishing/message/base.rb +73 -0
  24. data/lib/table_sync/publishing/message/batch.rb +14 -0
  25. data/lib/table_sync/publishing/message/raw.rb +54 -0
  26. data/lib/table_sync/publishing/message/single.rb +13 -0
  27. data/lib/table_sync/publishing/params/base.rb +66 -0
  28. data/lib/table_sync/publishing/params/batch.rb +23 -0
  29. data/lib/table_sync/publishing/params/raw.rb +7 -0
  30. data/lib/table_sync/publishing/params/single.rb +31 -0
  31. data/lib/table_sync/publishing/raw.rb +21 -0
  32. data/lib/table_sync/publishing/single.rb +65 -0
  33. data/lib/table_sync/publishing.rb +20 -5
  34. data/lib/table_sync/receiving/config.rb +6 -4
  35. data/lib/table_sync/receiving/handler.rb +25 -9
  36. data/lib/table_sync/receiving/model/active_record.rb +1 -1
  37. data/lib/table_sync/receiving.rb +0 -2
  38. data/lib/table_sync/setup/active_record.rb +22 -0
  39. data/lib/table_sync/setup/base.rb +67 -0
  40. data/lib/table_sync/setup/sequel.rb +26 -0
  41. data/lib/table_sync/utils/interface_checker.rb +2 -2
  42. data/lib/table_sync/version.rb +1 -1
  43. data/lib/table_sync.rb +31 -8
  44. data/table_sync.gemspec +7 -7
  45. metadata +58 -37
  46. data/.travis.yml +0 -34
  47. data/lib/table_sync/publishing/base_publisher.rb +0 -114
  48. data/lib/table_sync/publishing/batch_publisher.rb +0 -109
  49. data/lib/table_sync/publishing/orm_adapter/active_record.rb +0 -32
  50. data/lib/table_sync/publishing/orm_adapter/sequel.rb +0 -57
  51. data/lib/table_sync/publishing/publisher.rb +0 -129
@@ -0,0 +1,143 @@
1
+ # Configuration
2
+
3
+ Customization, configuration and other options.
4
+
5
+ ## Model Customization
6
+
7
+ There are methods you can define on a synched model to customize published messages for it.
8
+
9
+ ### `#attributes_for_sync`
10
+
11
+ Models can implement `#attributes_for_sync` to override which attributes are published for `update` and `create` events. If not present, all attributes are published.
12
+
13
+ ### `#attributes_for_destroy`
14
+
15
+ Models can implement `#attributes_for_destroy` to override which attributes are published for `destroy` events. If not present, `needle` (primary key) is published.
16
+
17
+ ### `#attributes_for_routing_key`
18
+
19
+ Models can implement `#attributes_for_routing_key` to override which attributes are given to the `routing_key_callable`. If not present, published attributes are given.
20
+
21
+ ### `#attributes_for_headers`
22
+
23
+ Models can implement `#attributes_for_headers` to override which attributes are given to the `headers_callable`. If not present, published attributes are given.
24
+
25
+ ### `.table_sync_model_name`
26
+
27
+ Models can implement `.table_sync_model_name` class method to override the model name used for publishing events. Default is a model class name.
28
+
29
+ ## Callables
30
+
31
+ Callables are defined once. TableSync will use them to dynamically resolve things like jobs, routing_key and headers.
32
+
33
+ ### Single publishing job (required for automatic and delayed publishing)
34
+
35
+ - `TableSync.single_publishing_job_class_callable` is a callable which should resolve to a class that calls TableSync back to actually publish changes.
36
+
37
+ It is expected to have `.perform_at(hash_with_options)` and it will be passed a hash with the following keys:
38
+
39
+ - `original_attributes` - serialized `original_attributes`
40
+ - `object_class` - model name
41
+ - `debounce_time` - pause between publishing messages
42
+ - `event` - type of event that happened to synched entity
43
+ - `perform_at` - time to perform the job at (depends on debounce)
44
+
45
+ Example:
46
+
47
+ ```ruby
48
+ TableSync.single_publishing_job_class_callable = -> { TableSync::Job }
49
+
50
+ class TableSync::Job < ActiveJob::Base
51
+ def perform(jsoned_attributes)
52
+ TableSync::Publishing::Single.new(
53
+ JSON.parse(jsoned_attributes),
54
+ ).publish_now
55
+ end
56
+
57
+ def self.perform_at(attributes)
58
+ set(wait_until: attributes.delete(:perform_at))
59
+ .perform_later(attributes.to_json)
60
+ end
61
+ end
62
+
63
+ # will enqueue the job described above
64
+
65
+ TableSync::Publishing::Single.new(
66
+ object_class: "User",
67
+ original_attributes: { id: 1, name: "Mark" }, # will be serialized!
68
+ debounce_time: 60,
69
+ event: :update,
70
+ ).publish_later
71
+ ```
72
+
73
+ ### Batch publishing job (required only for `TableSync::Publishing::Batch#publish_later`)
74
+
75
+ - `TableSync.batch_publishing_job_class_callable` is a callable which should resolve to a class that calls TableSync back to actually publish changes.
76
+
77
+ It is expected to have `.perform_later(hash_with_options)` and it will be passed a hash with the following keys:
78
+
79
+ - `original_attributes` - array of serialized `original_attributes`
80
+ - `object_class` - model name
81
+ - `event` - type of event that happened to synched entity
82
+ - `routing_key` - custom routing_key (optional)
83
+ - `headers` - custom headers (optional)
84
+
85
+ More often than not this job is not very useful, since it makes more sense to use `#publish_now` from an already existing job that does a lot of things (not just publishing messages).
86
+
87
+ ### Example
88
+
89
+ ```ruby
90
+ TableSync.batch_publishing_job_class_callable = -> { TableSync::BatchJob }
91
+
92
+ class TableSync::BatchJob < ActiveJob::Base
93
+ def perform(jsoned_attributes)
94
+ TableSync::Publishing::Batch.new(
95
+ JSON.parse(jsoned_attributes),
96
+ ).publish_now
97
+ end
98
+
99
+ def self.perform_later(attributes)
100
+ super(attributes.to_json)
101
+ end
102
+ end
103
+
104
+ TableSync::Publishing::Batch.new(
105
+ object_class: "User",
106
+ original_attributes: [{ id: 1, name: "Mark" }, { id: 2, name: "Bob" }], # will be serialized!
107
+ event: :create,
108
+ routing_key: :custom_key, # optional
109
+ headers: { type: "admin" }, # optional
110
+ ).publish_later
111
+ ```
112
+
113
+ ### Routing key callable (required)
114
+
115
+ - `TableSync.routing_key_callable` is a callable that resolves which routing key to use when publishing changes. It receives object class and published attributes or `#attributes_for_routing_key` (if defined).
116
+
117
+ Example:
118
+
119
+ ```ruby
120
+ TableSync.routing_key_callable = -> (klass, attributes) { klass.gsub('::', '_').tableize }
121
+ ```
122
+
123
+ ### Headers callable (required)
124
+
125
+ - `TableSync.headers_callable` is a callable that adds RabbitMQ headers which can be used in routing. It receives object class and published attributes or `#attributes_for_headers` (if defined).
126
+
127
+ One possible way of using it is defining a headers exchange and routing rules based on key-value pairs (which correspond to sent headers).
128
+
129
+ Example:
130
+
131
+ ```ruby
132
+ TableSync.routing_metadata_callable = -> (klass, attributes) { attributes.slice("project_id") }
133
+ ```
134
+
135
+ ## Other
136
+
137
+ - `TableSync.exchange_name` defines the exchange name used for publishing (optional, falls back to default Rabbit gem configuration).
138
+
139
+ - `TableSync.notifier` is a module that provides publish and recieve notifications.
140
+
141
+ - `TableSync.raise_on_empty_message` - raises an error on empty message if set to true.
142
+
143
+ - `TableSync.orm` - set ORM (ActiveRecord or Sequel) used to process given entities. Required!
@@ -0,0 +1,155 @@
1
+ # Manual Sync
2
+
3
+ There are two ways you can manually publish large amounts of data.
4
+
5
+ ### `TableSync::Publishing:Batch`
6
+
7
+ Easier to use, but does a lot of DB queries. May filter out invalid PK values.
8
+
9
+ #### Pros:
10
+
11
+ - requires less work
12
+ - it will automatically use methods for data customization (`#attributes_for_sync`, `#attributes_for_destroy`)
13
+ - you can be sure that data you publish is valid (more or less)
14
+ - serializes values for (`#publish_later`)
15
+
16
+ #### Cons:
17
+
18
+ - it queries database for each entity in batch (for `create` and `update`)
19
+ - it may also do a lot of queries if `#attributes_for_sync` contains additional data from other connected entities
20
+ - serializes values for (`#publish_later`); if your PK contains invalid values (ex. Date) they will be filtered out
21
+
22
+ ### `TableSync::Publishing:Raw`
23
+
24
+ More complex to use, but requires very few DB queries.
25
+ You are responsible for the data you send!
26
+
27
+ #### Pros:
28
+
29
+ - very customizable; only requirement - `object_class` must exist
30
+ - you can send whatever data you want
31
+
32
+ #### Cons:
33
+
34
+ - you have to manually prepare data for publishing
35
+ - you have to be really sure you are sending valid data
36
+
37
+ ## Tips
38
+
39
+ - **Don't make data batches too large!**
40
+
41
+ It may result in failure to process them. Good rule is to send approx. 5000 rows in one batch.
42
+
43
+ - **Make pauses between publishing data batches!**
44
+
45
+ Publishing without pause may overwhelm the receiving side. Either their background job processor (ex. Sidekiq) may clog with jobs, or their consumers may not be able to get messages from Rabbit server fast enough.
46
+
47
+ 1 or 2 seconds is a good wait period.
48
+
49
+ - **Do not use `TableSync::Publishing:Single` to send millions or even thousands of rows of data.**
50
+
51
+ Or just calling update on rows with automatic sync.
52
+ It WILL overwhelm the receiving side. Especially if they have some additional receiving logic.
53
+
54
+ - **On the receiving side don't create job with custom logic (if it exists) for every row in a batch.**
55
+
56
+ Better to process it whole. Otherwise three batches of 5000 will result in 15000 new jobs.
57
+
58
+ - **Send one test batch before publishing the rest of the data.**
59
+
60
+ Make sure it was received properly. This way you won't send a lot invalid messages.
61
+
62
+ - **Check the other arguments.**
63
+
64
+ - Ensure the routing_key is correct if you are using a custom one. Remember, that batch publishing ignores `#attributes_for_routing_key` on a model.
65
+ - Ensure that `object_class` is correct. And it belongs to entities you want to send.
66
+ - Ensure that you chose the correct event.
67
+ - If you have some logic depending on headers, ensure they are also correct. Remember, that batch publishing ignores `#attributes_for_headers` on a model.
68
+
69
+ - **You can check what you send before publishing with:**
70
+
71
+ ```ruby
72
+ TableSync::Publishing:Batch.new(...).message.message_params
73
+
74
+ TableSync::Publishing:Raw.new(...).message.message_params
75
+ ```
76
+
77
+ ## Examples
78
+
79
+ ### `TableSync::Publishing:Raw`
80
+
81
+ ```ruby
82
+ # For Sequel
83
+ # gem 'sequel-batches' or equivalent that will allow you to chunk data somehow
84
+ # or #each_page from Sequel
85
+
86
+ # this is a simple query
87
+ # they can be much more complex, with joins and other things
88
+ # just make sure that it results in a set of data you expect
89
+ data = User.in_batches(of: 5000).naked.select(:id, :name, :email)
90
+
91
+ data.each_with_index do |batch, i|
92
+ TableSync::Publishing::Raw.new(
93
+ object_class: "User",
94
+ original_attributes: batch,
95
+ event: :create,
96
+ routing_key: :custom_key, # optional
97
+ headers: { type: "admin" }, # optional
98
+ ).publish_now
99
+
100
+ # make a pause between batches
101
+ sleep 1
102
+
103
+ # for when you are sending from terminal
104
+ # allows you to keep an eye on progress
105
+ # you can create more complex output
106
+ puts "Batch #{i} sent!"
107
+ end
108
+
109
+ ```
110
+
111
+ #### Another way to gather data
112
+
113
+ If you don't want to create a data query (maybe it's too complex) but there is a lot of quereing in `#attributes_for_sync` and you are willing to trade a little bit of perfomance, you can try the following.
114
+
115
+ ```ruby
116
+ class User < Sequel
117
+ one_to_many :user_info
118
+
119
+ # For example our receiving side wants to know the ips user logged in under
120
+ # But doesn't want to sync the user_info
121
+ def attributes_for_sync
122
+ attributes.merge(
123
+ ips: user_info.ips
124
+ )
125
+ end
126
+ end
127
+
128
+ # to prevent the need to query for every piece of additional data we can user eager load
129
+ # and construct published data by calling #attributes_for_sync
130
+ # don't forget to chunk it into more managable sizes before trying to send
131
+ data = User.eager(:statuses).map { |user| user.attributes_for_sync }
132
+ ```
133
+ This way it will not make unnecessary queries.
134
+
135
+ ### `TableSync::Publishing::Batch`
136
+
137
+ Remember, it will query or initialize each row.
138
+
139
+ ```ruby
140
+ # You can just send ids.
141
+ data = User.in_batches(of: 5000).naked.select(:id)
142
+
143
+ data.each_with_index do |data, i|
144
+ TableSync::Publishing::Batch.new(
145
+ object_class: "User",
146
+ original_attributes: data,
147
+ event: :create,
148
+ routing_key: :custom_key, # optional
149
+ headers: { type: "admin" }, # optional
150
+ ).publish_now
151
+
152
+ sleep 1
153
+ puts "Batch #{i} sent!"
154
+ end
155
+ ```
@@ -0,0 +1,162 @@
1
+ # Publishers
2
+
3
+ There are three publishers you can use to send data.
4
+
5
+ - `TableSync::Publishing::Single` - sends one row with initialization.
6
+ - `TableSync::Publishing::Batch` - sends a batch of rows with initialization.
7
+ - `TableSync::Publishing::Raw` - sends raw data without checks.
8
+
9
+ ## Single
10
+
11
+ `TableSync::Publishing::Single` - sends one row with initialization.
12
+
13
+ This is a publisher called by `TableSync.sync(self)`.
14
+
15
+ ### Expected parameters:
16
+
17
+ - `object_class` - class (model) used to initialize published object
18
+ - `original_attributes` - attributes used to initialize `object_class` with
19
+ - `debounce_time` - minimum allowed time between delayed publishings
20
+ - `event` - type of event that happened to the published object (`create`, `update`, `destroy`); `update` by default
21
+
22
+ ### What it does (when uses `#publish_now`):
23
+ - takes in the `original_attributes`, `object_class`, `event`
24
+ - constantizes `object_class`
25
+ - extracts the primary key (`needle`) of the `object_class` from the `original_attributes`
26
+ - queries the database for the object with the `needle` (for `update` and `create`) or initializes the `object_class` with `original_attributes` (for `destroy`)
27
+ - constructs routing_key using `routing_key_callable` and `#attributes_for_routing_key` (if defined)
28
+ - constructs headers using `headers_callable` and `#attributes_for_headers` (if defined)
29
+ - publishes Rabbit message (uses attributes from queried/initialized object as data)
30
+ - sends notification (if set up)
31
+
32
+ ### What it does (when uses `#publish_later`):
33
+ - takes in the `original_attributes`, `object_class`, `debounce_time`, `event`
34
+ - serializes the `original_attributes`, silently filters out unserializable keys/values
35
+ - enqueues (or skips) the job with the `serialized_original_attributes` to be performed in time according to debounce
36
+ - job (if enqueued) calls `TableSync::Publishing::Single#publish_now` with `serialized_original_attributes` and the same `object_class`, `debounce_time`, `event`
37
+
38
+ ### Serialization
39
+
40
+ Currently allowed key/values are:
41
+ `NilClass`, `String`, `TrueClass`, `FalseClass`, `Numeric`, `Symbol`.
42
+
43
+ ### Job
44
+
45
+ Job is defined in `TableSync.single_publishing_job_class_callable` as a proc. Read more in [Configuration](docs/publishing/configuration.md).
46
+
47
+ ### Example #1 (send right now)
48
+
49
+ ```ruby
50
+ TableSync::Publishing::Single.new(
51
+ object_class: "User",
52
+ original_attributes: { id: 1, name: "Mark" },
53
+ debounce_time: 60, # useless for #publish _now, can be skipped
54
+ event: :create,
55
+ ).publish_now
56
+ ```
57
+
58
+ ### Example #2 (enqueue job)
59
+
60
+ ```ruby
61
+ TableSync::Publishing::Single.new(
62
+ object_class: "User",
63
+ original_attributes: { id: 1, name: "Mark" }, # will be serialized!
64
+ debounce_time: 60,
65
+ event: :update,
66
+ ).publish_later
67
+ ```
68
+
69
+ ## Batch
70
+
71
+ - `TableSync::Publishing::Batch` - sends a batch of rows with initialization.
72
+
73
+ ### Expected parameters:
74
+
75
+ - `object_class` - class (model) used to initialize published objects
76
+ - `original_attributes` - array of attributes used to initialize `object_class` with
77
+ - `event` - type of event that happened to the published objects (`create`, `update`, `destroy`); `update` by default
78
+ - `routing_key` - custom routing_key
79
+ - `headers` - custom headers
80
+
81
+ ### What it does (when uses `#publish_now`):
82
+ - takes in the `original_attributes`, `object_class`, `event`, `routing_key`, `headers`
83
+ - constantizes `object_class`
84
+ - extracts primary keys (`needles`) of the `object_class` from the array of `original_attributes`
85
+ - queries the database for the objects with `needles` (for `update` and `create`) or initializes the `object_class` with `original_attributes` (for `destroy`)
86
+ - constructs routing_key using `routing_key_callable` (ignores `#attributes_for_routing_key`) or uses `routing_key` if given
87
+ - constructs headers using `headers_callable` (ignores `#attributes_for_headers`) or uses `headers` if given
88
+ - publishes Rabbit message (uses attributes from queried/initialized objects as data)
89
+ - sends notification (if set up)
90
+
91
+ ### What it does (when uses `#publish_later`):
92
+ - takes in the `original_attributes`, `object_class`, `event`, `routing_key`, `headers`
93
+ - serializes the array of `original_attributes`, silently filters out unserializable keys/values
94
+ - enqueues the job with the `serialized_original_attributes`
95
+ - job calls `TableSync::Publishing::Batch#publish_now` with `serialized_original_attributes` and the same `object_class`, `event`, `routing_key`, `headers`
96
+
97
+ ### Serialization
98
+
99
+ Currently allowed key/values are:
100
+ `NilClass`, `String`, `TrueClass`, `FalseClass`, `Numeric`, `Symbol`.
101
+
102
+ ### Job
103
+
104
+ Job is defined in `TableSync.batch_publishing_job_class_callable` as a proc. Read more in [Configuration](docs/publishing/configuration.md).
105
+
106
+ ### Example #1 (send right now)
107
+
108
+ ```ruby
109
+ TableSync::Publishing::Batch.new(
110
+ object_class: "User",
111
+ original_attributes: [{ id: 1, name: "Mark" }, { id: 2, name: "Bob" }],
112
+ event: :create,
113
+ routing_key: :custom_key, # optional
114
+ headers: { type: "admin" }, # optional
115
+ ).publish_now
116
+ ```
117
+
118
+ ### Example #2 (enqueue job)
119
+
120
+ ```ruby
121
+ TableSync::Publishing::Batch.new(
122
+ object_class: "User",
123
+ original_attributes: [{ id: 1, name: "Mark" }, { id: 2, name: "Bob" }],
124
+ event: :create,
125
+ routing_key: :custom_key, # optional
126
+ headers: { type: "admin" }, # optional
127
+ ).publish_later
128
+ ```
129
+
130
+ ## Raw
131
+ - `TableSync::Publishing::Raw` - sends raw data without checks.
132
+
133
+ Be carefull with this publisher. There are no checks for the data sent.
134
+ You can send anything.
135
+
136
+ ### Expected parameters:
137
+
138
+ - `object_class` - model
139
+ - `original_attributes` - raw data that will be sent
140
+ - `event` - type of event that happened to the published objects (`create`, `update`, `destroy`); `update` by default
141
+ - `routing_key` - custom routing_key
142
+ - `headers` - custom headers
143
+
144
+ ### What it does (when uses `#publish_now`):
145
+ - takes in the `original_attributes`, `object_class`, `event`, `routing_key`, `headers`
146
+ - constantizes `object_class`
147
+ - constructs routing_key using `routing_key_callable` (ignores `#attributes_for_routing_key`) or uses `routing_key` if given
148
+ - constructs headers using `headers_callable` (ignores `#attributes_for_headers`) or uses `headers` if given
149
+ - publishes Rabbit message (uses `original_attributes` as is)
150
+ - sends notification (if set up)
151
+
152
+ ### Example
153
+
154
+ ```ruby
155
+ TableSync::Publishing::Raw.new(
156
+ object_class: "User",
157
+ original_attributes: [{ id: 1, name: "Mark" }, { id: 2, name: "Bob" }],
158
+ event: :create,
159
+ routing_key: :custom_key, # optional
160
+ headers: { type: "admin" }, # optional
161
+ ).publish_now
162
+ ```
data/docs/publishing.md CHANGED
@@ -1,147 +1,63 @@
1
- # Publishing changes
1
+ # Publishing
2
2
 
3
- Include `TableSync.sync(self)` into a Sequel or ActiveRecord model. `:if` and `:unless` are
4
- supported for Sequel and ActiveRecord
3
+ TableSync can be used to send data using RabbitMQ.
5
4
 
6
- Functioning `Rails.cache` is required
5
+ You can do in two ways. Automatic and manual.
6
+ Each one has its own pros and cons.
7
7
 
8
- Example:
9
-
10
- ```ruby
11
- class SomeModel < Sequel::Model
12
- TableSync.sync(self, { if: -> (*) { some_code } })
13
- end
14
- ```
15
-
16
- #### #attributes_for_sync
17
-
18
- Models can implement `#attributes_for_sync` to override which attributes are published. If not
19
- present, all attributes are published
8
+ Automatic is used to publish changes in realtime, as soon as the tracked entity changes.
9
+ Usually syncs one entity at a time.
20
10
 
21
- #### #attrs_for_routing_key
11
+ Manual allows to sync a lot of entities per message.
12
+ But demands greater amount of work and data preparation.
22
13
 
23
- Models can implement `#attrs_for_routing_key` to override which attributes are given to routing_key_callable. If not present, default attributes are given
14
+ ## Automatic
24
15
 
25
- #### #attrs_for_metadata
16
+ Include `TableSync.sync(self)` into a Sequel or ActiveRecord model.
26
17
 
27
- Models can implement `#attrs_for_metadata` to override which attributes are given to metadata_callable. If not present, default attributes are given
18
+ Options:
28
19
 
29
- #### .table_sync_model_name
20
+ - `if:` and `unless:` - Runs given proc in the scope of an instance. Skips sync on `false` for `if:` and on `true` for `unless:`.
21
+ - `on:` - specify events (`create`, `update`, `destroy`) to trigger sync on. Triggered for all of them without this option.
22
+ - `debounce_time` - min time period allowed between synchronizations.
30
23
 
31
- Models can implement `.table_sync_model_name` class method to override the model name used for
32
- publishing events. Default is model class name
24
+ Functioning `Rails.cache` is required.
33
25
 
34
- #### .table_sync_destroy_attributes(original_attributes)
26
+ How it works:
35
27
 
36
- Models can implement `.table_sync_destroy_attributes` class method to override the attributes
37
- used for publishing destroy events. Default is object's primary key
28
+ - `TableSync.sync(self)` - registers new callbacks (for `create`, `update`, `destroy`) for ActiveRecord model, and defines `after_create`, `after_update` and `after_destroy` callback methods for Sequel model.
38
29
 
39
- ## Configuration
40
-
41
- - `TableSync.publishing_job_class_callable` is a callable which should resolve to a ActiveJob
42
- subclass that calls TableSync back to actually publish changes (required)
30
+ - Callbacks call `TableSync::Publishing::Single#publish_later` with given options and object attributes. It enqueues a job which then publishes a message.
43
31
 
44
32
  Example:
45
33
 
46
34
  ```ruby
47
- class TableSync::Job < ActiveJob::Base
48
- def perform(*args)
49
- TableSync::Publisher.new(*args).publish_now
50
- end
35
+ class SomeModel < Sequel::Model
36
+ TableSync.sync(self, { if: -> (*) { some_code }, unless: -> (*) { some_code }, on: [:create, :update] })
51
37
  end
52
- ```
53
-
54
- - `TableSync.batch_publishing_job_class_callable` is a callable which should resolve to a ActiveJob
55
- subclass that calls TableSync batch publisher back to actually publish changes (required for batch publisher)
56
-
57
- - `TableSync.routing_key_callable` is a callable which resolves which routing key to use when
58
- publishing changes. It receives object class and attributes (required)
59
-
60
- Example:
61
-
62
- ```ruby
63
- TableSync.routing_key_callable = -> (klass, attributes) { klass.gsub('::', '_').tableize }
64
- ```
65
-
66
- - `TableSync.routing_metadata_callable` is a callable that adds RabbitMQ headers which can be
67
- used in routing (optional). One possible way of using it is defining a headers exchange and
68
- routing rules based on key-value pairs (which correspond to sent headers)
69
38
 
70
- Example:
71
-
72
- ```ruby
73
- TableSync.routing_metadata_callable = -> (klass, attributes) { attributes.slice("project_id") }
39
+ class SomeOtherModel < Sequel::Model
40
+ TableSync.sync(self)
41
+ end
74
42
  ```
75
43
 
76
- - `TableSync.exchange_name` defines the exchange name used for publishing (optional, falls back
77
- to default Rabbit gem configuration).
78
-
79
- - `TableSync.notifier` is a module that provides publish and recieve notifications.
80
-
81
- # Manual publishing
82
-
83
- `TableSync::Publisher.new(object_class, original_attributes, confirm: true, state: :updated, debounce_time: 45)`
84
- where state is one of `:created / :updated / :destroyed` and `confirm` is Rabbit's confirm delivery flag and optional param `debounce_time` determines debounce time in seconds, 1 minute by default.
85
-
86
- # Manual publishing with batches
87
-
88
- You can use `TableSync::BatchPublisher` to publish changes in batches (array of hashes in `attributes`).
44
+ ## Manual
89
45
 
90
- When using `TableSync::BatchPublisher`,` TableSync.routing_key_callable` is called as follows:
91
- `TableSync.routing_key_callable.call(klass, {})`, i.e. empty hash is passed instead of attributes.
92
- And `TableSync.routing_metadata_callable` is not called at all: metadata is set to empty hash.
93
-
94
- `TableSync::BatchPublisher.new(object_class, original_attributes_array, **options)`, where `original_attributes_array` is an array with hash of attributes of published objects and `options` is a hash of options.
95
-
96
- `options` consists of:
97
- - `confirm`, which is a flag for RabbitMQ, `true` by default
98
- - `routing_key`, which is a custom key used (if given) to override one from `TableSync.routing_key_callable`, `nil` by default
99
- - `push_original_attributes` (default value is `false`), if this option is set to `true`,
100
- original_attributes_array will be pushed to Rabbit instead of fetching records from database and sending their mapped attributes.
101
- - `headers`, which is an option for custom headers (can be used for headers exchanges routes), `nil` by default
102
- - `event`, which is an option for event specification (`:destroy` or `:update`), `:update` by default
46
+ Directly call one of the publishers. It's the best if you need to sync a lot of data.
47
+ This way you don't even need for the changes to occur.
103
48
 
104
49
  Example:
105
50
 
106
51
  ```ruby
107
- TableSync::BatchPublisher.new(
108
- "SomeClass",
109
- [{ id: 1 }, { id: 2 }],
110
- confirm: false,
111
- routing_key: "custom_routing_key",
112
- push_original_attributes: true,
113
- headers: { key: :value },
114
- event: :destroy,
115
- )
52
+ TableSync::Publishing::Batch.new(
53
+ object_class: "User",
54
+ original_attributes: [{ id: 1 }, { id: 2 }],
55
+ event: :update,
56
+ ).publish_now
116
57
  ```
117
58
 
118
- # Manual publishing with batches (Russian)
119
-
120
- С помощью класса `TableSync::BatchPublisher` вы можете опубликовать изменения батчами (массивом в `attributes`).
121
-
122
- При использовании `TableSync::BatchPublisher`, `TableSync.routing_key_callable` вызывается следующим образом:
123
- `TableSync.routing_key_callable.call(klass, {})`, то есть вместо аттрибутов передается пустой хэш.
124
- А `TableSync.routing_metadata_callable` не вызывается вовсе: в метадате устанавливается пустой хэш.
125
-
126
- `TableSync::BatchPublisher.new(object_class, original_attributes_array, **options)`, где `original_attributes_array` - массив с аттрибутами публикуемых объектов и `options`- это хэш с дополнительными опциями.
59
+ ## Read More
127
60
 
128
- `options` состоит из:
129
- - `confirm`, флаг для RabbitMQ, по умолчанию - `true`
130
- - `routing_key`, ключ, который (если указан) замещает ключ, получаемый из `TableSync.routing_key_callable`, по умолчанию - `nil`
131
- - `push_original_attributes` (значение по умолчанию `false`), если для этой опции задано значение true, в Rabbit будут отправлены original_attributes_array, вместо получения значений записей из базы непосредственно перед отправкой.
132
- - `headers`, опция для задания headers (можно использовать для задания маршрутов в headers exchange'ах), `nil` по умолчанию
133
- - `event`, опция для указания типа события (`:destroy` или `:update`), `:update` по умолчанию
134
-
135
- Example:
136
-
137
- ```ruby
138
- TableSync::BatchPublisher.new(
139
- "SomeClass",
140
- [{ id: 1 }, { id: 2 }],
141
- confirm: false,
142
- routing_key: "custom_routing_key",
143
- push_original_attributes: true,
144
- headers: { key: :value },
145
- event: :destroy,
146
- )
147
- ```
61
+ - [Publishers](publishing/publishers.md)
62
+ - [Configuration](publishing/configuration.md)
63
+ - [Manual Sync (examples)](publishing/manual.md)