Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

## Unreleased

- State where `async` waits when no worker runs. The `async` section of the
README and the runtime section of `docs/operations.md` now say that the
generator and the migrations start no role, so an application that serves
web requests alone leaves the message ready until
`bundle exec solid_objects start` runs the roles. The message is durable
and waits; it is not lost. `test/integration/background_pickup_test.rb`
pins it: the message reads `ready` and the actor state stays empty until a
worker runs. This matches solid-objects-js#22, which reported the same gap
for `runtime.run(signal)` in the Node package.

- Add `examples/at_least_once` and `bundle exec rake at_least_once`, an
executable proof that the at-least-once clause fires and that the
documented remedy absorbs it. One actor turn stages an effect that writes
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,12 @@ message = order.async(
).submit
```

`async` needs a running actor worker. Installing the engine and migrating the
schema starts no role, so a process that only serves web requests leaves the
message ready. Nothing is lost. The message waits until
`bundle exec solid_objects start` runs the roles. See
[Worker requirements](#worker-requirements) for the feature-by-role table.

Use `available_at:` to spread bulk work or delay one message:

```ruby
Expand Down
7 changes: 7 additions & 0 deletions docs/operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ Start all configured roles:
bundle exec solid_objects start
```

The generator and the migrations prepare the database and start nothing. A
process claims ready messages only after this command starts its roles, so an
application that serves web requests alone leaves every `async` message ready.
The message is durable and waits for the first process that runs the roles. A
direct call or an explicit `sync` needs no running role, because the caller's
own path executes it.

The command loads the host application's `app/actors` directories before
starting any runtime role, even when Rails eager loading is disabled. Actors in
the conventional directory do not need initializer references. The targeted
Expand Down
37 changes: 37 additions & 0 deletions test/integration/background_pickup_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

require "database_test_helper"

class BackgroundPickupTest < ActiveSupport::TestCase
class MailboxActor < SolidObjects::Actor
actor_type "background-pickup-mailbox"

attribute :delivered, default: 0

def receive
self.delivered += 1
end
end

test "leaves an async message ready until a worker runs the roles" do
message = MailboxActor.ref("inbox").async.receive

assert_equal "ready", message.status
assert_empty SolidObjects::Instance.find_by!(
actor_type: "background-pickup-mailbox", actor_id: "inbox"
).state

worker = SolidObjects::Worker.new
begin
worker.run_until_idle
ensure
worker.stop
end

assert_equal "completed", message.status
assert_equal(
{ "delivered" => 1 },
SolidObjects::Instance.find_by!(actor_type: "background-pickup-mailbox", actor_id: "inbox").state
)
end
end
Loading