本文へ移動
cccskills
無料GitHub で公開日本語紹介

connector-sink

Apache Iggyのストリームからメッセージを受け取り、データベースやHTTPなど外部システムへ送るSinkプラグインの作成・変更を支援します。

原文原文の説明を見る

Author a new Apache Iggy connector sink plugin under core/connectors/sinks/. Sinks consume messages from Apache Iggy streams and push them to an external system (DB, search engine, HTTP endpoint, object store). Load when creating, modifying, or reviewing a sink crate. Use for sink plugin authoring. NOT for runtime internals (see connector-runtime).

apache/iggyスター 5,223(GitHub 5,223 + cccskills 0)
連携ツールPostgreSQLMongoDB

実行スコア 未検証

インストール方法を見る

こんなときに便利

  • DBへ書き込むSinkを作りたいとき
  • HTTP連携用のSinkを追加したいとき
  • リトライやバッチ処理を見直したいとき

日本語での紹介

できること

Apache Iggyのストリームから受け取ったメッセージを、データベース、検索エンジン、HTTPエンドポイント、オブジェクトストアなどへ送るSinkプラグインの作成・変更・レビューを支援します。初期化時の接続確認、設定値の扱い、ペイロードやヘッダーの変換、バッチ送信、リトライ方針、終了時のフラッシュなど、Sink固有の実装上の要点を確認できます。メッセージの再配信に備えた冪等性や、外部サービスを使う統合テストも扱います。

こんなときに便利

Apache Iggyから外部サービスへデータを連携するプラグインを新しく作るときや、既存のSinkの設定・送信処理を変更するときに向いています。失敗時の再試行やバッチ処理を含めて、実装の確認をしたい場合にも使えます。

使い方の例

  • 「PostgreSQLに書き込むSinkプラグインの構成を作ってください」
  • 「このSinkのHTTPエラー分類とリトライ方針を確認してください」
  • 「外部サービスを使うSinkの統合テスト方針を整理してください」

注意点

実装対象はRustのcdylibプラグインです。外部サービスと連携するプラグインには、Dockerを使う統合テストの手順が示されています。SDKのSinkトレイト自体の変更や、ランタイム内部の変更は対象外です。

この紹介文は、公開されている SKILL.md をもとに AI(OpenAI Codex)が作成しました。正確な仕様は下の原文を確認してください。

含まれるファイル(2)

  • SKILL.md11.4 KB
  • TEMPLATE.md5.9 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Writing an Apache Iggy Connector Sink

A sink is a Rust cdylib that implements iggy_connector_sdk::Sink and exposes FFI symbols via the sink_connector! macro. The runtime loads it as .so/.dylib/.dll, polls Apache Iggy on its behalf, runs the transform chain, decodes via the configured Schema, and hands the sink batches of ConsumedMessage. The sink is responsible for getting them to the external system reliably and efficiently.

Universal connector rules (SecretString, benchmark, verbose flag, drop accounting, filter contract, exemplar patterns) live in connectors-overview. This skill covers only what's sink-specific.

Contents

STOP and ask the user before

  • Changing the SDK trait surface (Sink::open / consume / close) - that's an SDK change, not a plugin one.
  • Touching default batch_size, retry caps, or backoff defaults baked into existing in-tree sinks.
  • Promoting an Err variant to retryable when it previously was not - retrying bad data trips circuit breakers.
  • Adding a new sink that introduces a backend the runtime doesn't yet integration-test for.

Quick reference

  • Skeleton: TEMPLATE.md (load on demand when authoring).
  • Exemplars: stdout_sink (minimal), postgres_sink (DB + transient detection), http_sink (validation, batch modes, retry middleware), mongodb_sink (atomic counters), elasticsearch_sink / iceberg_sink (backend-specific idioms).

Hard rules

Lifecycle

  • Sink::consume takes &self - never &mut self. Mutable state goes behind tokio::sync::Mutex / AtomicU64. Prefer atomics for hot counters - mongodb_sink uses messages_processed: AtomicU64 + insertion_errors: AtomicU64 and avoids a state lock on the hot path entirely.
  • Sink::open builds the client AND tests connectivity. Fail fast with Error::InitError.
  • Sink::close flushes + drops resources. Take ownership via client: Option<Client> + .take(). sqlx pools have .close().await. reqwest/mongodb/elasticsearch clients just drop. Log final stats either way.

Config

  • Every runtime-tunable field is Option<T> with a default applied in new(). Forward-compat: adding a field doesn't break existing TOML.
  • Durations: Option<String>, parsed via humantime::Duration in new(). Two equivalent in-tree idioms - inline HumanDuration::from_str(&raw).map(|d| *d).unwrap_or_else(..) (random_source, postgres_source) or a local parse_duration helper (http_sink, sdk/src/retry.rs). Fall back to a default on parse failure with warn! - never panic. We do not use humantime_serde.
  • Conflict resolution: if two config fields can be in invalid relative ordering, fix it in new() + warn! - don't error. http_sink swaps retry_delay and max_retry_delay when reversed to avoid an ExponentialBackoff panic downstream.
  • Validation order: structural in new(), connectivity in open(), never in consume().

Payloads (efficiency-critical)

  • Dispatch on the Payload variant. Handle Json, Raw, Text and Proto at minimum. Proto holds text that is a JSON document when proto_convert had no descriptor or could not encode, and arbitrary text otherwise: call Payload::json_document() first and fall back to the text handling when it returns None. Unsupported -> Error::InvalidPayloadType or fall back to base64 (elasticsearch_sink).
  • For Payload::Json, call try_to_bytes(&self) - single-pass serialization without cloning the OwnedValue tree (sdk/src/lib.rs::Payload::try_to_bytes). Never payload.clone().try_into_vec().
  • To take a payload out of ConsumedMessage without cloning: std::mem::replace(&mut message.payload, Payload::Raw(vec![])). Standard pattern across http_sink::send_individual / send_ndjson / send_json_array.
  • Pre-allocate per-batch buffers with Vec::with_capacity(messages.len()) (or * factor for serialized bodies). Used across postgres_sink, mongodb_sink, quickwit_sink, elasticsearch_sink, http_sink.

Headers

  • message.headers: Option<BTreeMap<HeaderKey, HeaderValue>>. Check .is_empty() before iterating - runtime treats empty as None.
  • For binary values use v.as_raw() + base64. for text use v.to_string_value(). See http_sink::EncodedHeader.
  • BTreeMap for deterministic ordering. Don't collect into HashMap.

Errors

ScenarioSDK variantRetry?
Init / connectivity failureError::InitErrorn/a (fails open)
Bad config valueError::InvalidConfigValue(field)n/a
Single-message validation failureError::InvalidRecordValue(reason)no - skip + log
Transient backend (5xx, conn reset, ...)Error::HttpRequestFailed / Error::Connection / Error::CannotStoreDatayes
Permanent 4xx, schema mismatch, constraintError::PermanentHttpError / Error::SchemaMismatchno - retrying trips circuit breakers
I/O failure mid-write (parquet/iceberg)Error::WriteFailurecaller decides
Catalog commit failure (Iceberg)Error::CatalogCommitErrorno - not idempotent

Retry

  • SDK helpers cover the simple case: iggy_connector_sdk::retry::check_connectivity_with_retry(...) for open(), HttpRetryMiddleware for default 429/5xx/network policy on reqwest clients.
  • Custom strategies: reqwest-middleware + reqwest_retry::RetryTransientMiddleware::new_with_policy_and_strategy. http_sink defines its own HttpSinkRetryStrategy (honors success_status_codes, per-status decisions).
  • Non-HTTP clients: write is_transient_error(&e) mapping driver-specific codes. postgres_sink::is_transient_error maps SQLSTATEs 40001, 40P01, 57P01-03, 08000/03/06.
  • Retry loop: new connectors use iggy_connector_sdk::retry::retry_async(policy, context, should_retry, op) for anything that fails as Err. It owns attempt counting, backoff and the per-retry log, and returns RetryFailure { error, attempts, exhausted }; the caller logs the terminal failure.
  • Backoff only, for a loop that computes its own delay (it retries on an Ok response, carries a deadline, or reconnects between attempts): retry_backoff(base, retry, max), where retry is 1-based. exponential_backoff is the 0-based primitive underneath, and it applies no jitter; call it directly only when the delay must be exact, as sdk/src/source.rs::nack_retry_delay needs for its tests.
  • Cap retries at 3 total attempts.

Idempotency

Runtime retries on any Err - same batch can be redelivered. In-tree guarantees:

  • Postgres (postgres_sink::build_batch_insert_query): PK on id, but plain INSERT (no ON CONFLICT). Duplicate retry triggers 23505, is_transient_error does NOT mark it transient -> error propagates. Adding ON CONFLICT (id) DO NOTHING is a known improvement.
  • MongoDB: composite _id from stream:topic:partition:message_id, via insert_many(docs).ordered(false). Per-document duplicate-key errors don't abort the batch - effective idempotency under retry.
  • Elasticsearch (bulk_index_documents): bulk action specifies only _index, no _id -> ES auto-generates ids -> NOT idempotent. Extensions should add "_id".
  • HTTP: endpoint-dependent. Document in the plugin README.
  • Iceberg: transactional commit. Error::CatalogCommitError documents that the txn is consumed on commit(). Rebuild-then-retry can duplicate data - callers must check the catalog first.

When writing a new sink, prefer dedup-on-write using the message id field. Mongo's upsert-style is the cleanest reference.

Batching

  • Default batch_size: 100. Tune per-backend.
  • Chunk via messages.chunks(self.batch_size). Do not buffer across consume() - runtime already batches at the consumer-poll boundary.
  • For HTTP backends support multiple batch modes when applicable (individual / ndjson / json_array / raw). See http_sink::BatchMode.

Logging

info!("Opened <connector> connector ID: {}, endpoint: <redacted>", self.id);
debug!("Processing batch of {} messages, offset: {}", batch.len(), offset);
warn!("Retry {attempt}/{max} for <connector> ID: {}, reason: {error}", self.id);
error!("Failed to <op> for <connector> ID: {}, error: {error}", self.id);
info!("Closed <connector> connector ID: {}, processed: {}", self.id, count);

Use literal API field names as labels (offset=, current_offset=).

Common pitfalls

  1. Missing [lib] crate-type = ["cdylib", "lib"] - runtime can't dlopen a regular rlib.
  2. Cloning the whole Payload::Json to serialize - use try_to_bytes(&self).
  3. Holding Mutex across .await when the locked region does I/O.
  4. &mut self on consume - won't compile. you need interior mutability.
  5. Returning the first error and dropping subsequent batches - track last_err, process all, return.
  6. Forgetting to map PermanentHttpError - retries hammer the backend with bad data.
  7. Mutating config in consume() - config is a snapshot from new(). Reload requires runtime restart.
  8. Logging the connection string. Redact at construction: http_sink::sanitize_url_for_log populates HttpSink.log_url.

Tests

Unit tests at EOF of src/lib.rs. See connector-testing for BDD naming + test_config() helper.

Real-infra integration tests live under core/integration/tests/connectors/<backend>/ using #[iggy_harness] + a backend fixture that spins up Docker via testcontainers-modules. Plugins integrating with external services must have an integration test. Reference: core/integration/tests/connectors/postgres/postgres_sink.rs + fixtures/postgres/.

Before declaring done

cargo fmt --all
cargo sort --no-format --workspace
cargo clippy -p iggy_connector_<name>_sink --all-targets -- -D warnings
cargo test -p iggy_connector_<name>_sink

# Integration tests (filter by name; integration crate has no per-area target):
cargo test -p integration -- connectors::<backend>::<test_name>

Update core/connectors/sinks/README.md and add a sample TOML under core/connectors/runtime/example_config/connectors/.


Discussion / help: see AGENTS.md.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

コメント

ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。

まだコメントはありません。最初のコメントを書いてみませんか。

送信するとすぐに公開されます。メールアドレスや電話番号などの個人情報は書かないでください。URL は 2 つまでです。

0 / 1000 文字

このフォームは reCAPTCHA で保護されており、Google のプライバシーポリシーと利用規約が適用されます。

同じリポジトリのスキル

connector-review

無料概要あり

Apache Iggyのコネクター変更を複数の専門視点から厳しくレビューし、指摘ごとに独立した検証を行って、修正が必要な問題を整理します。

  • コネクターのPRをマージ前に確認したいとき
  • ブランチの変更を専門視点でレビューしたいとき
  • 指摘の妥当性を独立して検証したいとき
apache/iggy5,2232026年10月29日 更新

connector-runtime

無料概要あり

Apache Iggyとコネクタープラグインをつなぐランタイムの開発に使います。読み込みやデータ転送、状態保存、設定、HTTP API、メトリクスなどの変更箇所を把握できます。

  • プラグインの読み込みや管理を変更したいとき
  • ソース・シンクの転送処理を調べたいとき
  • 状態保存や設定取得を修正したいとき
apache/iggy5,2232026年10月29日 更新

connector-sdk

無料概要あり

Apache Iggy Connectors SDKのスキーマ、エンコーダー、デコーダー、エラー型やFFIなどを追加・変更するときに、関連箇所と互換性への影響を整理するスキルです。

  • SDKにスキーマ形式を追加したいとき
  • ストリーム変換器を実装したいとき
  • 公開APIやFFIの変更を検討するとき
apache/iggy5,2232026年10月29日 更新

connector-source

無料概要あり

データベース、API、キューなど外部システムをポーリングし、Apache Iggyのストリームへメッセージを送るSourceプラグインの作成・変更を支援します。

  • DBのデータを取り込むSourceを作りたいとき
  • APIの情報を定期取得したいとき
  • カーソルとACK・NACK処理を確認したいとき
apache/iggy5,2232026年10月29日 更新

connector-testing

無料概要あり

Apache Iggyのコネクター向けに、ユニットテストや実サービスを使う統合テストを設計・作成し、命名規則や状態復元などのテスト慣例に沿って確認します。

  • コネクターのユニットテストを追加したいとき
  • ソースの状態復元を検証したいとき
  • 実サービスを使う統合テストを書くとき
apache/iggy5,2232026年10月29日 更新

connector-transform

無料概要あり

Apache Iggyコネクターのメッセージにフィールド追加・削除や形式変換などの処理を加える変換機能を設計し、設定連携やテストまで整えます。

  • メッセージにフィールドを追加したいとき
  • 条件に応じてメッセージを除外したいとき
  • データ形式を変換したいとき
apache/iggy5,2232026年10月29日 更新

apache のスキルをすべて見る

このスキルの問題を報告する