Dowser.Migration.Adapter behaviour (Dowser.Client v0.5.0)

View Source

What Dowser.Migrator needs from a backend package to run migrations against its engine: the cluster requests, and where it keeps which migrations ran.

A backend's repo names its adapter — use Dowser.OpenSearch.Repo defines __migration_adapter__/0 — so an application never names one.

Every callback takes the repo to send the request to (anything a :repo option takes) and returns :ok/{:ok, result} or {:error, reason}. Index names are physical indices unless a callback says otherwise; settings are flat and index.-prefixed ("index.number_of_replicas"), mappings and bodies have string keys.

use Dowser.Migration.Adapter gives a default dynamic_setting?/1.

Tracking

The adapter keeps one record per migration run — %{"version" => integer, "name" => string, "indices" => [string], "dropped" => [string], "separators" => %{index => string}}, given and returned as they are — and one lock: a document only one migrator can create, holding "owner" and "state" — what a copy in progress has changed, for mix dowser.recover after a crash.

Summary

Types

An index as get_indices/2 returns it: "mappings", "settings" (flat, without the index. prefix) and "aliases" (names).

Callbacks

Blocks writes to an index, once the writes in flight are done (the add-block API, not the setting).

The migrations recorded as run, in any order.

Creates an index from a create-index request body.

Deletes an index.

Whether the engine changes setting key (relative to index) on a live index; anything else is changed by copying the documents.

Creates what tracking needs (its index) when missing.

The indices matching names — aliases, index names or patterns — keyed by physical name; none for a name matching nothing.

The lock in place, or nil.

A background task's status, as the tasks API returns it: "completed", then "response" (with "failures", "total", "created") or "error".

Takes the lock, creating it with lock; {:error, {:locked, lock}} with the one in place when another migrator holds it.

Adds fields — and replaces _meta — with a put-mapping request body.

Updates settings; a nil value resets one.

Records a migration as run.

Starts copying source into dest in the background, through script when not nil; returns the task's id.

Lifts an index's write block.

Moves alias name from index from to index to, atomically.

Releases the lock.

Removes a migration's record.

Replaces the lock's content.

Types

index()

@type index() :: %{required(String.t()) => term()}

An index as get_indices/2 returns it: "mappings", "settings" (flat, without the index. prefix) and "aliases" (names).

repo()

@type repo() :: Dowser.Repo.t()

result()

@type result() :: :ok | {:error, term()}

Callbacks

add_write_block(repo, index)

@callback add_write_block(repo(), index :: String.t()) :: result()

Blocks writes to an index, once the writes in flight are done (the add-block API, not the setting).

applied(repo)

@callback applied(repo()) :: {:ok, [map()]} | {:error, term()}

The migrations recorded as run, in any order.

create_index(repo, index, body)

@callback create_index(repo(), index :: String.t(), body :: map()) :: result()

Creates an index from a create-index request body.

delete_index(repo, index)

@callback delete_index(repo(), index :: String.t()) :: result()

Deletes an index.

dynamic_setting?(key)

@callback dynamic_setting?(key :: String.t()) :: boolean()

Whether the engine changes setting key (relative to index) on a live index; anything else is changed by copying the documents.

ensure_tracking(repo)

@callback ensure_tracking(repo()) :: result()

Creates what tracking needs (its index) when missing.

get_indices(repo, names)

@callback get_indices(repo(), names :: [String.t()]) ::
  {:ok, %{required(String.t()) => index()}} | {:error, term()}

The indices matching names — aliases, index names or patterns — keyed by physical name; none for a name matching nothing.

get_lock(repo)

@callback get_lock(repo()) :: {:ok, map() | nil} | {:error, term()}

The lock in place, or nil.

get_task(repo, task)

@callback get_task(repo(), task :: String.t()) :: {:ok, map()} | {:error, term()}

A background task's status, as the tasks API returns it: "completed", then "response" (with "failures", "total", "created") or "error".

lock(repo, lock)

@callback lock(repo(), lock :: map()) :: result()

Takes the lock, creating it with lock; {:error, {:locked, lock}} with the one in place when another migrator holds it.

put_mapping(repo, index, body)

@callback put_mapping(repo(), index :: String.t(), body :: map()) :: result()

Adds fields — and replaces _meta — with a put-mapping request body.

put_settings(repo, index, settings)

@callback put_settings(repo(), index :: String.t(), settings :: map()) :: result()

Updates settings; a nil value resets one.

record(repo, record)

@callback record(repo(), record :: map()) :: result()

Records a migration as run.

reindex(repo, source, dest, script)

@callback reindex(repo(), source :: String.t(), dest :: String.t(), script :: map() | nil) ::
  {:ok, String.t()} | {:error, term()}

Starts copying source into dest in the background, through script when not nil; returns the task's id.

remove_write_block(repo, index)

@callback remove_write_block(repo(), index :: String.t()) :: result()

Lifts an index's write block.

swap_alias(repo, name, from, to)

@callback swap_alias(repo(), name :: String.t(), from :: String.t(), to :: String.t()) ::
  result()

Moves alias name from index from to index to, atomically.

unlock(repo)

@callback unlock(repo()) :: result()

Releases the lock.

unrecord(repo, version)

@callback unrecord(repo(), version :: integer()) :: result()

Removes a migration's record.

update_lock(repo, lock)

@callback update_lock(repo(), lock :: map()) :: result()

Replaces the lock's content.