Packages
Optional Oban workers for cursor-aware Pipedrive sync with rate-limit snooze. Depends on ex_pipedrive; the host app owns Oban, Ecto, and TokenStore.
Current section
Files
Jump to
Current section
Files
ex_pipedrive_oban
README.md
README.md
# ExPipedriveOban
Optional [Oban](https://hex.pm/packages/oban) workers for **cursor-aware Pipedrive
sync**. Core [`ex_pipedrive`](https://hex.pm/packages/ex_pipedrive) stays free of
Oban; this package owns the worker, unique-job keys, and rate-limit snooze.
The host application already runs Oban (and Ecto). This package does not start
an Oban instance or a repo.
## Installation
```elixir
def deps do
[
{:ex_pipedrive, "~> 0.2.0"},
{:ex_pipedrive_oban, "~> 0.1.0"}
]
end
```
Add a Pipedrive queue to your existing Oban config:
```elixir
config :my_app, Oban,
repo: MyApp.Repo,
queues: [pipedrive: 5]
```
## Source callback
Implement `ExPipedriveOban.Source` to build a client and persist each page:
```elixir
defmodule MyApp.PipedriveSync do
@behaviour ExPipedriveOban.Source
@impl true
def client(%{"tenant_id" => tenant_id}) do
ExPipedrive.Client.from_token_store(MyApp.PipedriveTokenStore, tenant_id)
end
@impl true
def handle_page("deals", deals, %{"tenant_id" => tenant_id}) do
MyApp.Deals.upsert_many(tenant_id, deals)
:ok
end
def handle_page(_resource, _rows, _args), do: :ok
end
```
Prefer `retry: false` on the Tesla client so Oban snooze owns 429 backoff
(core retries 429 a few times first if you leave the default on).
## Enqueue a deals sync
```elixir
%{
"source" => "Elixir.MyApp.PipedriveSync",
"tenant_id" => "acme",
"resource" => "deals",
"list_opts" => %{"status" => "open"}
}
|> ExPipedriveOban.SyncWorker.new()
|> Oban.insert()
```
`ExPipedriveOban.Workers.SyncDeals.enqueue/3` is a thin helper for that map.
Kickoff jobs are unique per `tenant_id` + `resource` so two full syncs do not
overlap. Continuation pages insert with `unique: false`.
On `{:error, %ExPipedrive.Error{kind: :rate_limited}}`, the worker
`{:snooze, seconds}` using `Retry-After` / `x-ratelimit-reset` when present
(default 15s).
Supported `resource` values: `deals`, `persons`, `organizations` (each via
`list_page/2`).
## Version coupling
| This package | Core |
|---|---|
| `0.1.x` | `ex_pipedrive ~> 0.2` |
Inside this git repo Mix uses a **path** dependency on core. Hex consumers get
`{:ex_pipedrive, "~> 0.2"}`.
```bash
cd packages/ex_pipedrive_oban
HEX_PUBLISH=1 mix hex.publish
```
Hex: [`ex_pipedrive_oban` 0.1.0](https://hex.pm/packages/ex_pipedrive_oban).
## Development
```bash
mix deps.get
mix test
mix format --check-formatted
mix credo --strict
```