The first version of tobox (v0.3.0) has been released.

tobox implements the consumer side of the transactional outbox pattern, providing a simple way to configure your event handlers.

* https://gitlab.com/honeyryderchuck/tobox
* https://microservices.io/patterns/data/transactional-outbox.html

tobox executes your handlers in a worker pool. The worker pool can be thread-based (default) or fiber-based.

It uses the “SKIP LOCKED” SQL dialect to support concurrent polling for events from the database outbox table.

It ships with plugins for sentry, datadog and zeitwerk. The plugin system is itself very simple, so you can add your own custom logic around event processing.

It can be used as a background job processor, although it’s best used in tandem with an existing framework.

Here are the updates since the last release:

## [0.3.0] - 2022-12-12

### Features

#### Inbox

Implementation of the "inbox pattern", which ensures that events are processed to completion only once.

```ruby
# create an inbox table and reference it
create_table(:inbox) do
  column :id, :varchar, null: true, primary_key: true
  # ...
create_table(:outbox) do
  column :inbox_id, :varchar
  foreign_key :inbox_id, :inbox
  # ...

# tobox.rb
inbox_table :inbox
inbox_column :inbox_id

# event production
DB[:outbox].insert(event_type: "order_created", inbox_id: "order_created_#{order.id}", ....
DB[:outbox].insert(event_type: "billing_event_started", inbox_id: "billing_event_started_#{order.id}", ....
```

## [0.2.0] - 2022-12-05

### Features

#### Ordered event processing

When the outbox table contains a `:group_id` table (and the producer fills up events with it), then a group of events with the same `:group_id` will be processed one by one, by order of insertion.

```ruby
# migration
create_table(:outbox) do
  column :message_group_id, :integer

# tobox.rb
message_group_column :group_id

# event production
DB[:outbox].insert(event_type: "order_created", message_group_id: order.id, ....
DB[:outbox].insert(event_type: "billing_event_started", message_group_id: order.id, ....

# order_created handled first, billing_event_started only after
```

#### on_error_worker callback

The config option `on_error_worker { |error| }` gets called when an error happens in a worker **before** events are processed (p.ex. when the database connection becomes unhealthy). You can use it to report such errors to an error reporting system (the `sentry` plugin relies on it).

```ruby
# tobox.rb
on_error_worker { |error| Sentry.capture_exception(error, hint: { background: false }) }
```

### Bugfixes

Thread workers: when errors happen which bring down the workers (such as database becoming unresponsive), workers will be restarted.