solid_objects 0.1.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 (178) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +17 -0
  3. data/MIT-LICENSE +19 -0
  4. data/README.md +744 -0
  5. data/Rakefile +40 -0
  6. data/app/controllers/solid_objects/application_controller.rb +23 -0
  7. data/app/controllers/solid_objects/dead_letters_controller.rb +23 -0
  8. data/app/controllers/solid_objects/instances_controller.rb +29 -0
  9. data/app/helpers/solid_objects/actor_helper.rb +25 -0
  10. data/app/models/solid_objects/broadcast.rb +10 -0
  11. data/app/models/solid_objects/claimed_message.rb +14 -0
  12. data/app/models/solid_objects/dead_letter.rb +13 -0
  13. data/app/models/solid_objects/effect.rb +10 -0
  14. data/app/models/solid_objects/instance.rb +93 -0
  15. data/app/models/solid_objects/message.rb +53 -0
  16. data/app/models/solid_objects/process.rb +13 -0
  17. data/app/models/solid_objects/ready_message.rb +10 -0
  18. data/app/models/solid_objects/record.rb +17 -0
  19. data/app/models/solid_objects/reminder.rb +9 -0
  20. data/app/views/solid_objects/dead_letters/index.html.erb +26 -0
  21. data/app/views/solid_objects/instances/index.html.erb +24 -0
  22. data/app/views/solid_objects/instances/show.html.erb +35 -0
  23. data/benchmark/activation_cache.rb +5 -0
  24. data/benchmark/ask_latency.rb +5 -0
  25. data/benchmark/claim.rb +5 -0
  26. data/benchmark/cold_actors.rb +5 -0
  27. data/benchmark/concurrent_actors.rb +5 -0
  28. data/benchmark/enqueue.rb +5 -0
  29. data/benchmark/hot_actor.rb +5 -0
  30. data/benchmark/processing.rb +5 -0
  31. data/benchmark/query_count.rb +5 -0
  32. data/benchmark/support.rb +271 -0
  33. data/config/routes.rb +8 -0
  34. data/db/migrate/20260805000000_create_solid_objects_tables.rb +319 -0
  35. data/docs/adr/0001-postgresql-backend.md +21 -0
  36. data/docs/adr/0002-jsonb-actor-state.md +21 -0
  37. data/docs/adr/0003-mailbox-ordering.md +30 -0
  38. data/docs/adr/0004-activation-leasing.md +21 -0
  39. data/docs/adr/0005-fencing-tokens.md +25 -0
  40. data/docs/adr/0006-at-least-once-delivery.md +24 -0
  41. data/docs/adr/0007-transactional-outbox.md +21 -0
  42. data/docs/adr/0008-actor-communication.md +21 -0
  43. data/docs/adr/0009-realtime-updates.md +21 -0
  44. data/docs/adr/0010-state-versioning.md +29 -0
  45. data/docs/adr/0011-wake-up-strategy.md +34 -0
  46. data/docs/adr/0012-not-active-jobs.md +21 -0
  47. data/docs/adr/0013-database-adapters.md +48 -0
  48. data/docs/architecture.md +615 -0
  49. data/docs/benchmarks.md +26 -0
  50. data/docs/correctness.md +124 -0
  51. data/docs/database-schema.md +111 -0
  52. data/docs/development.md +87 -0
  53. data/docs/implementation-plan.md +518 -0
  54. data/docs/operations.md +123 -0
  55. data/docs/realtime.md +51 -0
  56. data/docs/research/solid_queue.md +545 -0
  57. data/docs/roadmap.md +53 -0
  58. data/docs/security.md +61 -0
  59. data/docs/state-migrations.md +46 -0
  60. data/examples/application/README.md +16 -0
  61. data/examples/application/app/actors/chat_room_actor.rb +34 -0
  62. data/examples/application/app/actors/shopping_cart_actor.rb +79 -0
  63. data/examples/application/app/controllers/cart_controller.rb +54 -0
  64. data/examples/application/app/controllers/chat_rooms_controller.rb +44 -0
  65. data/examples/application/app/views/actors/chat_room_actor/_messages.html.erb +8 -0
  66. data/examples/application/app/views/actors/shopping_cart_actor/_summary.html.erb +10 -0
  67. data/examples/application/app/views/cart/show.html.erb +13 -0
  68. data/examples/application/app/views/chat_rooms/show.html.erb +8 -0
  69. data/examples/application/config/initializers/solid_objects.rb +23 -0
  70. data/examples/application/config/routes.rb +20 -0
  71. data/exe/solid_objects +9 -0
  72. data/lib/generators/solid_objects/install_generator.rb +21 -0
  73. data/lib/generators/solid_objects/templates/solid_objects.rb +13 -0
  74. data/lib/solid_objects/action_cable_broadcast_adapter.rb +19 -0
  75. data/lib/solid_objects/activation.rb +183 -0
  76. data/lib/solid_objects/activation_manager.rb +102 -0
  77. data/lib/solid_objects/actor.rb +271 -0
  78. data/lib/solid_objects/actor_channel.rb +29 -0
  79. data/lib/solid_objects/actor_definition.rb +212 -0
  80. data/lib/solid_objects/actor_registry.rb +65 -0
  81. data/lib/solid_objects/actor_snapshot.rb +42 -0
  82. data/lib/solid_objects/actor_view.rb +117 -0
  83. data/lib/solid_objects/broadcast_executor.rb +162 -0
  84. data/lib/solid_objects/cli.rb +118 -0
  85. data/lib/solid_objects/client.rb +153 -0
  86. data/lib/solid_objects/configuration.rb +168 -0
  87. data/lib/solid_objects/context.rb +41 -0
  88. data/lib/solid_objects/database_adapter.rb +82 -0
  89. data/lib/solid_objects/database_adapters/mysql.rb +22 -0
  90. data/lib/solid_objects/database_adapters/postgresql.rb +17 -0
  91. data/lib/solid_objects/database_adapters/sqlite.rb +12 -0
  92. data/lib/solid_objects/dead_letter_manager.rb +47 -0
  93. data/lib/solid_objects/dom_identity.rb +38 -0
  94. data/lib/solid_objects/effect_executor.rb +235 -0
  95. data/lib/solid_objects/effect_registry.rb +34 -0
  96. data/lib/solid_objects/engine.rb +33 -0
  97. data/lib/solid_objects/errors.rb +65 -0
  98. data/lib/solid_objects/executor.rb +290 -0
  99. data/lib/solid_objects/instrumentation.rb +10 -0
  100. data/lib/solid_objects/lease.rb +172 -0
  101. data/lib/solid_objects/lease_renewer.rb +70 -0
  102. data/lib/solid_objects/log_subscriber.rb +29 -0
  103. data/lib/solid_objects/mailbox.rb +178 -0
  104. data/lib/solid_objects/message_reference.rb +52 -0
  105. data/lib/solid_objects/process_registry.rb +143 -0
  106. data/lib/solid_objects/reference.rb +96 -0
  107. data/lib/solid_objects/reminder_scheduler.rb +168 -0
  108. data/lib/solid_objects/serialization.rb +99 -0
  109. data/lib/solid_objects/state.rb +111 -0
  110. data/lib/solid_objects/stream_name.rb +29 -0
  111. data/lib/solid_objects/stream_token.rb +59 -0
  112. data/lib/solid_objects/supervisor.rb +87 -0
  113. data/lib/solid_objects/turbo_stream_renderer.rb +35 -0
  114. data/lib/solid_objects/version.rb +5 -0
  115. data/lib/solid_objects/wake_up.rb +28 -0
  116. data/lib/solid_objects/worker.rb +139 -0
  117. data/lib/solid_objects.rb +118 -0
  118. data/sig/generated/controllers/solid_objects/application_controller.rbs +10 -0
  119. data/sig/generated/controllers/solid_objects/dead_letters_controller.rbs +11 -0
  120. data/sig/generated/controllers/solid_objects/instances_controller.rbs +11 -0
  121. data/sig/generated/helpers/solid_objects/actor_helper.rbs +8 -0
  122. data/sig/generated/lib/generators/solid_objects/install_generator.rbs +13 -0
  123. data/sig/generated/lib/solid_objects/action_cable_broadcast_adapter.rbs +8 -0
  124. data/sig/generated/lib/solid_objects/activation.rbs +65 -0
  125. data/sig/generated/lib/solid_objects/activation_manager.rbs +36 -0
  126. data/sig/generated/lib/solid_objects/actor.rbs +183 -0
  127. data/sig/generated/lib/solid_objects/actor_channel.rbs +8 -0
  128. data/sig/generated/lib/solid_objects/actor_definition.rbs +117 -0
  129. data/sig/generated/lib/solid_objects/actor_registry.rbs +36 -0
  130. data/sig/generated/lib/solid_objects/actor_snapshot.rbs +28 -0
  131. data/sig/generated/lib/solid_objects/actor_view.rbs +56 -0
  132. data/sig/generated/lib/solid_objects/broadcast_executor.rbs +55 -0
  133. data/sig/generated/lib/solid_objects/cli.rbs +31 -0
  134. data/sig/generated/lib/solid_objects/client.rbs +35 -0
  135. data/sig/generated/lib/solid_objects/configuration.rbs +147 -0
  136. data/sig/generated/lib/solid_objects/context.rbs +56 -0
  137. data/sig/generated/lib/solid_objects/database_adapter.rbs +42 -0
  138. data/sig/generated/lib/solid_objects/database_adapters/mysql.rbs +16 -0
  139. data/sig/generated/lib/solid_objects/database_adapters/postgresql.rbs +13 -0
  140. data/sig/generated/lib/solid_objects/database_adapters/sqlite.rbs +10 -0
  141. data/sig/generated/lib/solid_objects/dead_letter_manager.rbs +16 -0
  142. data/sig/generated/lib/solid_objects/dom_identity.rbs +20 -0
  143. data/sig/generated/lib/solid_objects/effect_executor.rbs +82 -0
  144. data/sig/generated/lib/solid_objects/effect_registry.rbs +24 -0
  145. data/sig/generated/lib/solid_objects/engine.rbs +7 -0
  146. data/sig/generated/lib/solid_objects/errors.rbs +64 -0
  147. data/sig/generated/lib/solid_objects/executor.rbs +60 -0
  148. data/sig/generated/lib/solid_objects/instrumentation.rbs +8 -0
  149. data/sig/generated/lib/solid_objects/lease.rbs +57 -0
  150. data/sig/generated/lib/solid_objects/lease_renewer.rbs +42 -0
  151. data/sig/generated/lib/solid_objects/log_subscriber.rbs +11 -0
  152. data/sig/generated/lib/solid_objects/mailbox.rbs +46 -0
  153. data/sig/generated/lib/solid_objects/message_reference.rbs +37 -0
  154. data/sig/generated/lib/solid_objects/process_registry.rbs +46 -0
  155. data/sig/generated/lib/solid_objects/reference.rbs +45 -0
  156. data/sig/generated/lib/solid_objects/reminder_scheduler.rbs +55 -0
  157. data/sig/generated/lib/solid_objects/serialization.rbs +31 -0
  158. data/sig/generated/lib/solid_objects/state.rbs +72 -0
  159. data/sig/generated/lib/solid_objects/stream_name.rbs +11 -0
  160. data/sig/generated/lib/solid_objects/stream_token.rbs +19 -0
  161. data/sig/generated/lib/solid_objects/supervisor.rbs +38 -0
  162. data/sig/generated/lib/solid_objects/turbo_stream_renderer.rbs +14 -0
  163. data/sig/generated/lib/solid_objects/version.rbs +5 -0
  164. data/sig/generated/lib/solid_objects/wake_up.rbs +24 -0
  165. data/sig/generated/lib/solid_objects/worker.rbs +56 -0
  166. data/sig/generated/lib/solid_objects.rbs +41 -0
  167. data/sig/generated/models/solid_objects/broadcast.rbs +6 -0
  168. data/sig/generated/models/solid_objects/claimed_message.rbs +6 -0
  169. data/sig/generated/models/solid_objects/dead_letter.rbs +6 -0
  170. data/sig/generated/models/solid_objects/effect.rbs +6 -0
  171. data/sig/generated/models/solid_objects/instance.rbs +25 -0
  172. data/sig/generated/models/solid_objects/message.rbs +22 -0
  173. data/sig/generated/models/solid_objects/process.rbs +6 -0
  174. data/sig/generated/models/solid_objects/ready_message.rbs +6 -0
  175. data/sig/generated/models/solid_objects/record.rbs +8 -0
  176. data/sig/generated/models/solid_objects/reminder.rbs +6 -0
  177. data/sig/support/framework.rbs +37 -0
  178. metadata +467 -0
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ # rbs_inline: enabled
2
+
3
+ require "bundler/gem_tasks"
4
+ require "fileutils"
5
+ require "rake/testtask"
6
+
7
+ Rake::TestTask.new do |task|
8
+ task.libs << "test"
9
+ task.pattern = "test/**/*_test.rb"
10
+ end
11
+
12
+ desc "Generate RBS signatures from inline annotations"
13
+ task :rbs do
14
+ FileUtils.rm_rf(File.expand_path("sig/generated", __dir__))
15
+ sh "bundle exec rbs-inline --base lib --base app --output sig/generated lib app"
16
+ FileUtils.rm_f(File.expand_path("sig/generated/lib/generators/solid_objects/templates/solid_objects.rbs", __dir__))
17
+ sh "bundle exec rbs -I sig/generated -I sig/support validate"
18
+ end
19
+
20
+ desc "Run Standard Ruby"
21
+ task :standard do
22
+ sh "bundle exec standardrb"
23
+ end
24
+
25
+ desc "Run Solid Queue's RuboCop policy"
26
+ task :rubocop do
27
+ sh "bundle exec rubocop"
28
+ end
29
+
30
+ desc "Type-check generated inline RBS signatures"
31
+ task :steep do
32
+ sh "bundle exec steep check"
33
+ end
34
+
35
+ desc "Scan the Rails engine for security warnings"
36
+ task :security do
37
+ sh "bundle exec brakeman --force --no-pager -q ."
38
+ end
39
+
40
+ task default: %i[test standard rubocop rbs steep security]
@@ -0,0 +1,23 @@
1
+ # rbs_inline: enabled
2
+
3
+ module SolidObjects
4
+ class ApplicationController < ActionController::Base
5
+ protect_from_forgery with: :exception
6
+ before_action :authorize_administration!
7
+
8
+ private
9
+
10
+ # @rbs () -> void
11
+ def authorize_administration!
12
+ authorized = SolidObjects.configuration.authorize_administration.call(
13
+ action: action_name,
14
+ resource: controller_name,
15
+ resource_id: params[:id],
16
+ authorization_context: self
17
+ )
18
+ return if authorized
19
+
20
+ raise Unauthorized, "actor administration is not authorized"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # rbs_inline: enabled
2
+
3
+ module SolidObjects
4
+ class DeadLettersController < ApplicationController
5
+ # @rbs () -> void
6
+ def index
7
+ @dead_letters = DeadLetter.order(last_failed_at: :desc, id: :desc).limit(250)
8
+ respond_to do |format|
9
+ format.html
10
+ format.json { render json: @dead_letters }
11
+ end
12
+ end
13
+
14
+ # @rbs () -> void
15
+ def retry
16
+ message_reference = SolidObjects.dead_letters.retry(
17
+ params[:id].to_i,
18
+ authorization_context: self
19
+ )
20
+ redirect_to dead_letters_path, notice: "Retried as message #{message_reference.id}"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ # rbs_inline: enabled
2
+
3
+ module SolidObjects
4
+ class InstancesController < ApplicationController
5
+ # @rbs () -> void
6
+ def index
7
+ @instances = Instance.order(updated_at: :desc, id: :desc).limit(250)
8
+ respond_to do |format|
9
+ format.html
10
+ format.json { render json: @instances }
11
+ end
12
+ end
13
+
14
+ # @rbs () -> void
15
+ def show
16
+ @instance = Instance.find(params[:id])
17
+ @messages = @instance.messages.order(sequence: :desc).limit(250)
18
+ respond_to do |format|
19
+ format.html
20
+ format.json do
21
+ render json: {
22
+ instance: @instance,
23
+ messages: @messages
24
+ }
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,25 @@
1
+ # rbs_inline: enabled
2
+
3
+ module SolidObjects
4
+ module ActorHelper
5
+ # @rbs (Reference, ?authorization_context: untyped) { (ActorView) -> untyped } -> untyped
6
+ def solid_object(reference, authorization_context: self, &block)
7
+ actor = ActorView.new(
8
+ reference:,
9
+ view_context: self,
10
+ authorization_context:
11
+ )
12
+ subscription = tag.turbo_cable_stream_source(
13
+ channel: "SolidObjects::ActorChannel",
14
+ token: StreamToken.generate(reference)
15
+ )
16
+ content = capture(actor, &block)
17
+
18
+ content_tag(
19
+ :div,
20
+ safe_join([ subscription, content ]),
21
+ id: DomIdentity.scope(reference)
22
+ )
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,10 @@
1
+ # rbs_inline: enabled
2
+
3
+ module SolidObjects
4
+ class Broadcast < Record
5
+ self.table_name = SolidObjects.table_name(:broadcasts)
6
+
7
+ belongs_to :message, class_name: "SolidObjects::Message"
8
+ belongs_to :instance, class_name: "SolidObjects::Instance"
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ # rbs_inline: enabled
2
+
3
+ module SolidObjects
4
+ class ClaimedMessage < Record
5
+ self.table_name = SolidObjects.table_name(:claimed_messages)
6
+
7
+ belongs_to :message, class_name: "SolidObjects::Message", inverse_of: :claimed_message
8
+ belongs_to :instance, class_name: "SolidObjects::Instance", inverse_of: :claimed_messages
9
+ belongs_to :process_record,
10
+ class_name: "SolidObjects::Process",
11
+ foreign_key: :process_id,
12
+ optional: true
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ # rbs_inline: enabled
2
+
3
+ module SolidObjects
4
+ class DeadLetter < Record
5
+ self.table_name = SolidObjects.table_name(:dead_letters)
6
+
7
+ belongs_to :message, class_name: "SolidObjects::Message", inverse_of: :dead_letter
8
+ belongs_to :instance, class_name: "SolidObjects::Instance"
9
+ belongs_to :retried_message,
10
+ class_name: "SolidObjects::Message",
11
+ optional: true
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ # rbs_inline: enabled
2
+
3
+ module SolidObjects
4
+ class Effect < Record
5
+ self.table_name = SolidObjects.table_name(:effects)
6
+
7
+ belongs_to :message, class_name: "SolidObjects::Message"
8
+ belongs_to :instance, class_name: "SolidObjects::Instance"
9
+ end
10
+ end
@@ -0,0 +1,93 @@
1
+ # rbs_inline: enabled
2
+
3
+ module SolidObjects
4
+ class Instance < Record
5
+ self.table_name = SolidObjects.table_name(:instances)
6
+
7
+ belongs_to :activation_owner,
8
+ class_name: "SolidObjects::Process",
9
+ optional: true,
10
+ inverse_of: :instances
11
+ has_many :messages,
12
+ class_name: "SolidObjects::Message",
13
+ inverse_of: :instance,
14
+ dependent: :destroy
15
+ has_many :ready_messages,
16
+ class_name: "SolidObjects::ReadyMessage",
17
+ inverse_of: :instance,
18
+ dependent: :destroy
19
+ has_many :claimed_messages,
20
+ class_name: "SolidObjects::ClaimedMessage",
21
+ inverse_of: :instance,
22
+ dependent: :destroy
23
+
24
+ before_validation :supply_defaults
25
+
26
+ validates :actor_type, :actor_id, presence: true, length: { maximum: 191 }
27
+
28
+ class << self
29
+ # @rbs (?actor_type: String?) -> ActiveRecord::Relation[Instance]
30
+ def active(actor_type: nil)
31
+ relation = where(paused_at: nil)
32
+ actor_type ? relation.where(actor_type:) : relation
33
+ end
34
+
35
+ # @rbs (quiet_for: Numeric, ?now: Time) -> ActiveRecord::Relation[Instance]
36
+ def without_pending_work(quiet_for:, now: SolidObjects.database_adapter.database_now)
37
+ cutoff = now - quiet_for
38
+ where("COALESCE(last_used_at, created_at) <= ?", cutoff)
39
+ .where.not(id: ReadyMessage.select(:instance_id))
40
+ .where.not(id: ClaimedMessage.select(:instance_id))
41
+ .where.not(
42
+ id: Reminder.where(status: "scheduled").select(:instance_id)
43
+ )
44
+ end
45
+
46
+ # @rbs (actor_type: String, owner: ActiveRecord::Relation[untyped] | Class) -> ActiveRecord::Relation[Instance]
47
+ def orphaned(actor_type:, owner:)
48
+ owner_relation = owner.is_a?(ActiveRecord::Relation) ? owner : owner.all
49
+ owner_class = owner_relation.klass
50
+ owner_table = owner_class.arel_table
51
+ owner_primary_key = owner_table[owner_class.primary_key]
52
+ cast_type = Arel::Nodes::SqlLiteral.new(owner_id_cast_type)
53
+ cast_id = Arel::Nodes::NamedFunction.new(
54
+ "CAST",
55
+ [ Arel::Nodes::As.new(owner_primary_key, cast_type) ]
56
+ )
57
+ owner_ids = owner_relation
58
+ .except(:select)
59
+ .select(cast_id)
60
+
61
+ where(actor_type:).where.not(actor_id: owner_ids)
62
+ end
63
+
64
+ # @rbs (actor_type: String, actor_ids: Array[String]) -> Hash[String, Hash[String, untyped]]
65
+ def states_for(actor_type:, actor_ids:)
66
+ where(actor_type:, actor_id: actor_ids)
67
+ .pluck(:actor_id, :state)
68
+ .to_h
69
+ end
70
+
71
+ private
72
+
73
+ # @rbs () -> String
74
+ def owner_id_cast_type
75
+ case connection.adapter_name
76
+ when /mysql/i
77
+ "CHAR"
78
+ when /postgres/i
79
+ "VARCHAR"
80
+ else
81
+ "TEXT"
82
+ end
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ # @rbs () -> void
89
+ def supply_defaults
90
+ self.state ||= {}
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,53 @@
1
+ # rbs_inline: enabled
2
+
3
+ module SolidObjects
4
+ class Message < Record
5
+ self.table_name = SolidObjects.table_name(:messages)
6
+
7
+ belongs_to :instance, class_name: "SolidObjects::Instance", inverse_of: :messages
8
+ has_one :ready_message,
9
+ class_name: "SolidObjects::ReadyMessage",
10
+ inverse_of: :message,
11
+ dependent: :destroy
12
+ has_one :claimed_message,
13
+ class_name: "SolidObjects::ClaimedMessage",
14
+ inverse_of: :message,
15
+ dependent: :destroy
16
+ has_one :dead_letter,
17
+ class_name: "SolidObjects::DeadLetter",
18
+ inverse_of: :message,
19
+ dependent: :destroy
20
+
21
+ before_validation :supply_defaults
22
+
23
+ validates :message_kind, inclusion: { in: %w[tell ask internal] }
24
+
25
+ # @rbs () -> bool
26
+ def ready?
27
+ ready_message.present?
28
+ end
29
+
30
+ # @rbs () -> bool
31
+ def claimed?
32
+ claimed_message.present?
33
+ end
34
+
35
+ # @rbs () -> bool
36
+ def completed?
37
+ completed_at.present?
38
+ end
39
+
40
+ # @rbs () -> bool
41
+ def dead?
42
+ dead_letter.present?
43
+ end
44
+
45
+ private
46
+
47
+ # @rbs () -> void
48
+ def supply_defaults
49
+ self.arguments ||= {}
50
+ self.available_at ||= enqueued_at || Time.current
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,13 @@
1
+ # rbs_inline: enabled
2
+
3
+ module SolidObjects
4
+ class Process < Record
5
+ self.table_name = SolidObjects.table_name(:processes)
6
+
7
+ has_many :instances,
8
+ class_name: "SolidObjects::Instance",
9
+ foreign_key: :activation_owner_id,
10
+ inverse_of: :activation_owner,
11
+ dependent: :nullify
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ # rbs_inline: enabled
2
+
3
+ module SolidObjects
4
+ class ReadyMessage < Record
5
+ self.table_name = SolidObjects.table_name(:ready_messages)
6
+
7
+ belongs_to :message, class_name: "SolidObjects::Message", inverse_of: :ready_message
8
+ belongs_to :instance, class_name: "SolidObjects::Instance", inverse_of: :ready_messages
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ # rbs_inline: enabled
2
+
3
+ module SolidObjects
4
+ class Record < ActiveRecord::Base
5
+ self.abstract_class = true
6
+
7
+ class << self
8
+ # @rbs () -> void
9
+ def configure_connection
10
+ connection_configuration = SolidObjects.configuration.connects_to
11
+ return unless connection_configuration
12
+
13
+ connects_to(**connection_configuration)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ # rbs_inline: enabled
2
+
3
+ module SolidObjects
4
+ class Reminder < Record
5
+ self.table_name = SolidObjects.table_name(:reminders)
6
+
7
+ belongs_to :instance, class_name: "SolidObjects::Instance"
8
+ end
9
+ end
@@ -0,0 +1,26 @@
1
+ <h1>Dead letters</h1>
2
+
3
+ <table>
4
+ <thead>
5
+ <tr>
6
+ <th>Actor</th>
7
+ <th>Message</th>
8
+ <th>Attempts</th>
9
+ <th>Error</th>
10
+ <th>Failed</th>
11
+ <th></th>
12
+ </tr>
13
+ </thead>
14
+ <tbody>
15
+ <% @dead_letters.each do |dead_letter| %>
16
+ <tr>
17
+ <td><%= dead_letter.actor_type %>(<%= dead_letter.actor_id %>)</td>
18
+ <td><%= dead_letter.message_name %></td>
19
+ <td><%= dead_letter.attempts %></td>
20
+ <td><%= dead_letter.exception_class %>: <%= dead_letter.exception_message %></td>
21
+ <td><%= dead_letter.last_failed_at %></td>
22
+ <td><%= button_to "Retry", retry_dead_letter_path(dead_letter), method: :post %></td>
23
+ </tr>
24
+ <% end %>
25
+ </tbody>
26
+ </table>
@@ -0,0 +1,24 @@
1
+ <h1>Actors</h1>
2
+
3
+ <table>
4
+ <thead>
5
+ <tr>
6
+ <th>Type</th>
7
+ <th>ID</th>
8
+ <th>State version</th>
9
+ <th>Generation</th>
10
+ <th>Last used</th>
11
+ </tr>
12
+ </thead>
13
+ <tbody>
14
+ <% @instances.each do |instance| %>
15
+ <tr>
16
+ <td><%= link_to instance.actor_type, instance_path(instance) %></td>
17
+ <td><%= instance.actor_id %></td>
18
+ <td><%= instance.state_version %></td>
19
+ <td><%= instance.activation_generation %></td>
20
+ <td><%= instance.last_used_at %></td>
21
+ </tr>
22
+ <% end %>
23
+ </tbody>
24
+ </table>
@@ -0,0 +1,35 @@
1
+ <h1><%= @instance.actor_type %>(<%= @instance.actor_id %>)</h1>
2
+
3
+ <dl>
4
+ <dt>State version</dt>
5
+ <dd><%= @instance.state_version %></dd>
6
+ <dt>Activation generation</dt>
7
+ <dd><%= @instance.activation_generation %></dd>
8
+ <dt>Activation owner</dt>
9
+ <dd><%= @instance.activation_owner_id || "inactive" %></dd>
10
+ </dl>
11
+
12
+ <h2>State</h2>
13
+ <pre><%= JSON.pretty_generate(@instance.state) %></pre>
14
+
15
+ <h2>Recent messages</h2>
16
+ <table>
17
+ <thead>
18
+ <tr>
19
+ <th>Sequence</th>
20
+ <th>Name</th>
21
+ <th>Attempts</th>
22
+ <th>Completed</th>
23
+ </tr>
24
+ </thead>
25
+ <tbody>
26
+ <% @messages.each do |message| %>
27
+ <tr>
28
+ <td><%= message.sequence %></td>
29
+ <td><%= message.message_name %></td>
30
+ <td><%= message.attempt_count %></td>
31
+ <td><%= message.completed_at %></td>
32
+ </tr>
33
+ <% end %>
34
+ </tbody>
35
+ </table>
@@ -0,0 +1,5 @@
1
+ # rbs_inline: enabled
2
+
3
+ require_relative "support"
4
+
5
+ SolidObjectsBenchmark.activation_cache
@@ -0,0 +1,5 @@
1
+ # rbs_inline: enabled
2
+
3
+ require_relative "support"
4
+
5
+ SolidObjectsBenchmark.ask_latency
@@ -0,0 +1,5 @@
1
+ # rbs_inline: enabled
2
+
3
+ require_relative "support"
4
+
5
+ SolidObjectsBenchmark.claim
@@ -0,0 +1,5 @@
1
+ # rbs_inline: enabled
2
+
3
+ require_relative "support"
4
+
5
+ SolidObjectsBenchmark.cold_actors
@@ -0,0 +1,5 @@
1
+ # rbs_inline: enabled
2
+
3
+ require_relative "support"
4
+
5
+ SolidObjectsBenchmark.concurrent_actors
@@ -0,0 +1,5 @@
1
+ # rbs_inline: enabled
2
+
3
+ require_relative "support"
4
+
5
+ SolidObjectsBenchmark.enqueue
@@ -0,0 +1,5 @@
1
+ # rbs_inline: enabled
2
+
3
+ require_relative "support"
4
+
5
+ SolidObjectsBenchmark.hot_actor
@@ -0,0 +1,5 @@
1
+ # rbs_inline: enabled
2
+
3
+ require_relative "support"
4
+
5
+ SolidObjectsBenchmark.processing
@@ -0,0 +1,5 @@
1
+ # rbs_inline: enabled
2
+
3
+ require_relative "support"
4
+
5
+ SolidObjectsBenchmark.query_count