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

connector-sdk

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

原文原文の説明を見る

Extend or modify the Apache Iggy Connectors SDK (`core/connectors/sdk/`). Use when adding a new `Schema` variant, a new `StreamDecoder`/`StreamEncoder`, a new `Error` variant, modifying the `Sink`/`Source`/`Transform` trait surface, the FFI macros, or the `retry`/`api`/`convert` modules. NOT for writing plugins - use `connector-sink` or `connector-source` for those.

apache/iggyスター 5,223(GitHub 5,223 + cccskills 0)

実行スコア 未検証

インストール方法を見る

こんなときに便利

  • SDKにスキーマ形式を追加したいとき
  • ストリーム変換器を実装したいとき
  • 公開APIやFFIの変更を検討するとき

日本語での紹介

できること

Apache Iggy Connectors SDKを拡張・変更するときに、スキーマ、ペイロード、エンコーダー、デコーダー、エラー型、Sink・Source・Transformのトレイト、FFIマクロ、リトライ処理など、変更に関係する箇所を確認できます。スキーマを追加する場合は、変換処理や表示、SDKのREADME、往復テストまで更新対象を整理します。FFIをまたぐ型やシリアライズ形式、公開トレイトの変更がプラグインに与える影響も扱います。

こんなときに便利

SDKの新しいデータ形式やストリーム変換を追加するとき、公開APIやFFIの変更を検討するときに向いています。プラグイン全体に波及する互換性の変更を見落としたくない開発者にも役立ちます。プラグイン自体の作成手順ではなく、SDK側の変更を対象にしています。

使い方の例

  • 「SDKに新しいSchema形式を追加するための変更箇所を整理してください」
  • 「StreamDecoderを追加する際の実装方針とテストを確認してください」
  • 「このSinkトレイト変更が既存プラグインに与える影響を調べてください」

注意点

Apache 2.0のライセンスヘッダーが新規ファイルに必要です。公開トレイト、FFIのレイアウトやシンボル、シリアライズ形式などの重大な変更では、原文に記載された手順に従い、利用者への確認や関連プラグインとの調整が必要です。RustのCargoコマンドによる検証手順が示されています。

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

含まれるファイル(1)

  • SKILL.md13.3 KB

SKILL.md(原文)

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

Extending the Apache Iggy Connectors SDK

The SDK (core/connectors/sdk/) is the stable contract between the runtime and every plugin. Changes ripple to every sink/source in-tree and every third-party plugin. Treat the public surface as a versioned API.

Universal connector rules (benchmark, SecretString, drop accounting, exemplar patterns) live in connectors-overview. This skill covers SDK-level changes only.

Contents

STOP and ask the user before

  • Bumping the SDK MAJOR version or changing any #[repr(C)] layout - misaligns every pre-built plugin .so.
  • Changing Sink / Source / Transform / StreamDecoder / StreamEncoder trait signatures - cascades through every plugin.
  • Removing or renaming a Schema variant or Error variant - decoders/encoders pinned to it. downstream pattern matches break.
  • Changing wire serialization (postcard / rmp_serde / serde_json) for any FFI / state / config payload.
  • Changing FFI macro return codes or function names (iggy_*_open / consume / handle / close) - runtime + plugins both need lockstep update.

File map

sdk/src/
├── lib.rs              Traits (Sink, Source, StreamDecoder, StreamEncoder),
│                       Payload, Schema, ConnectorState, Error enum, FFI message structs.
├── sink.rs             SinkContainer + sink_connector! macro (FFI plumbing).
├── source.rs           SourceContainer + source_connector! macro (FFI plumbing).
├── api.rs              ConnectorStatus, ConnectorStats (feature = "api").
├── convert.rs          owned_value_into_serde_json / owned_value_to_serde_json (simd_json ⇄ serde_json bridge).
├── log.rs              CallbackLayer for tracing across FFI.
├── retry.rs            retry_async + RetryPolicy, CircuitBreaker, HttpRetryMiddleware.
├── decoders/           One per schema: json, raw, text, proto, flatbuffer, avro.
├── encoders/           Mirror of decoders.
└── transforms/         add_fields, delete_fields, update_fields, filter_fields,
                        unwrap_envelope, proto_convert, flatbuffer_convert, avro_convert.

Cardinal rules

  1. Apache 2.0 license header on every new file.
  2. Send + Sync on every public trait (FFI runs across thread pools).
  3. #[repr(C)] on every type that crosses FFI (Schema, TopicMetadata, MessagesMetadata, RawMessage, ProducedMessages, ConsumedMessage, DecodedMessage, etc. in lib.rs). Adding fields requires bumping the SDK version - existing plugins built against the old layout will misalign on postcard::from_bytes.
  4. postcard for FFI message serialization (handled by SinkContainer::consume, SourceContainer's handle_messages). MessagePack (rmp_serde) for ConnectorState. JSON (serde_json) only for human-editable config that crosses FFI. Don't mix.
  5. simd_json::OwnedValue for JSON payloads, not serde_json::Value. Use convert::owned_value_into_serde_json as a bridge when you own the value (the common case - it moves strings instead of copying them); fall back to the borrowing convert::owned_value_to_serde_json only when you still need the OwnedValue afterward.
  6. BTreeMap for headers - deterministic ordering. Never HashMap on the wire.
  7. No breaking changes to Sink/Source/StreamDecoder/StreamEncoder/Transform trait signatures without coordinating with all in-tree plugins in the same PR.
  8. A Schema variant that changes meaning is as breaking as a new variant. The discriminant crosses FFI unchanged, so a plugin built against the old SDK keeps decoding it the old way and misreads every batch with no error anywhere. Same process as a trait change: bump the SDK minor version, update every in-tree plugin in the same PR, and state in the PR description that plugins built against the previous SDK must be rebuilt.

Adding a new Schema variant

The Schema enum (in lib.rs) is #[repr(C)] - it crosses FFI. Touch points to update in one PR:

  1. Schema enum: add variant with #[strum(to_string = "...")] matching the serde(rename_all="snake_case") form.
  2. Payload enum: add a matching variant carrying the deserialized form.
  3. Payload::try_into_vec - consuming bytes-out path.
  4. Payload::try_to_bytes - borrowing bytes-out path. For non-trivial payloads (parsed trees), implement a no-clone serialization, not a clone() + serialize. See the Payload::Json arm for the canonical optimization.
  5. Payload::schema() - variant → Schema. The runtime tags every sink batch from this, so a missing arm will not compile but a wrong one silently mislabels the batch.
  6. Payload::Display.
  7. Schema::try_into_payload - bytes → Payload, for a tag naming a wire format (the source path).
  8. Payload::try_from_schema - bytes → Payload, for a tag that came from Payload::schema() (the sink path). The exact inverse of item 5.
  9. Schema::decoder() - factory returning Arc<dyn StreamDecoder>.
  10. Schema::encoder() - factory returning Arc<dyn StreamEncoder>.
  11. New decoders/<name>.rs and encoders/<name>.rs.
  12. Update the schema list in sdk/README.md.
  13. Tests: round-trip encode/decode, error paths. Payload::schema() must round-trip through Payload::try_from_schema, with no exceptions: every variant survives that trip and the test is table-driven over all of them.

Miss any of these → silent failures at runtime (typically Error::InvalidPayloadType or surprising decoder behavior in plugin code).

Adding a StreamDecoder / StreamEncoder

Pattern from decoders/json.rs::JsonStreamDecoder:

pub struct MyStreamDecoder;        // unit struct if stateless

impl StreamDecoder for MyStreamDecoder {
    fn schema(&self) -> Schema { Schema::MyFormat }
    fn decode(&self, payload: Vec<u8>) -> Result<Payload, Error> {
        // Decode payload bytes into Payload::MyFormat(...).
        // Errors: Error::CannotDecode(Schema::MyFormat), Error::InvalidJsonPayload, etc.
    }
}

For stateful decoders (proto/avro/flatbuffer) holding schema descriptors:

  • Store the schema state directly in the struct (config, message_descriptor, schema). The instance is built once and wrapped in Arc<dyn> for sharing - it must be Send + Sync but does not need additional locking if construction-time loading is final.
  • Provide two constructors when schema loading can fail: lenient new(config) -> Self (logs + degrades) AND strict try_new(config) -> Result<Self, Error> (fail-fast). Plus a Default impl for the no-schema case. Canonical example: sdk/src/decoders/avro.rs exports all three (AvroStreamDecoder::new, ::try_new, Default).
  • If you genuinely need to mutate the schema after construction (e.g., a update_config method), use &mut self plus std::mem::replace(&mut self.config, new_config) to swap without cloning the old value. Live pattern: sdk/src/decoders/avro.rs::AvroStreamDecoder::update_config and sdk/src/encoders/avro.rs::AvroStreamEncoder::update_config.
  • A fresh decoder instance is created via Schema::decoder() on each call (it returns Arc<dyn StreamDecoder>), so per-decoder caching of shared mutable state is the wrong abstraction.

Adding a new Error variant

The Error enum (in lib.rs) is Clone + PartialEq + Eq + Hash. New variants must preserve these. Guidelines:

  • Use existing variants first. Only add a new one if the failure mode is distinct in handling, not just description. InvalidConfigValue(String) covers most "bad config" cases.
  • Carry context as String - don't add a struct unless multiple discrete fields are needed by callers programmatically.
  • Document retry semantics in the docstring. Existing variants (PermanentHttpError, CatalogCommitError, TransactionApplyError) document retry behavior - mirror that style.
  • Place near related variants to keep the enum readable top-to-bottom.

Modifying Sink / Source / Transform traits

Breaking changes. Required process:

  1. Document migration in the SDK changelog (and connectors/sdk/README.md).
  2. Update every in-tree plugin in the same PR. CI builds them all.
  3. Bump SDK minor version.
  4. Note in PR description: dynamic plugins compiled against the old SDK version will fail to load with mismatched FFI symbols.

Non-breaking additions (new default method, new struct field with #[serde(default)], new variant on a non-exhaustive enum) are preferable.

FFI macros (sink_connector!, source_connector!)

The macros (in sink.rs and source.rs) generate:

  • iggy_<kind>_open(id, config_ptr, config_len, [state_ptr, state_len,] log_callback) -> i32
  • iggy_sink_consume(id, ...) / iggy_source_handle(id, callback) -> i32
  • iggy_<kind>_close(id) -> i32
  • iggy_<kind>_version() -> *const c_char (static lifetime, from env!("CARGO_PKG_VERSION"))

Invariants:

  • Duplicate-ID guard returns -1 if the caller reopens an ID without closing first. Don't remove this - it prevents silent buffered-data loss.
  • INSTANCES: Lazy<DashMap<u32, SinkContainer<$type>>> (and SourceContainer<$type> mirror) is the only mutable global the macro introduces - keep it that way.
  • Return codes: 0 success, -1 invalid call, 1 open failure. Don't repurpose.

Changes to the FFI signature must update runtime/src/main.rs::{SourceApi, SinkApi} in the same PR.

Payload::try_to_bytes(&self) is non-negotiable for JSON

Plugin authors call this on every consumed message. The implementation in lib.rs::Payload::try_to_bytes documents why it skips the deep OwnedValue clone - replacing O(n) clone + O(n) serialize with O(n) serialize. If you add a new variant requiring a parsed tree, do the same: serialize in place, don't clone.

Retry helpers (retry.rs)

  • CircuitBreaker: threshold + cooldown, try_lock() on the success path to avoid hot-path contention.
  • retry_async(policy, context, should_retry, op): the retry loop for anything failing as Err. Owns attempt counting, backoff and the per-retry log; returns RetryFailure { error, attempts, exhausted } so callers write their own terminal log.
  • retry_backoff(base, retry, max): backoff only, for a loop that computes its own delay. retry is 1-based. exponential_backoff is the 0-based primitive underneath and applies no jitter, so call it directly only when the delay must be exact (source.rs::nack_retry_delay, whose tests assert exact values).
  • HttpRetryMiddleware: integrates with reqwest-middleware. Retries 429 + 5xx + network errors. Honors Retry-After on 429 and 5xx as a floor over the computed backoff, capped at a one-hour MAX_RETRY_AFTER, not max_delay.
  • max_retries = total attempts including the first try, not extra retries. Document if you change this convention. meilisearch_sink is the standing exception: its max_retries / max_open_retries count retries after the first, as its README states.
  • New helpers must take Duration (not u64 millis) on the public API. Internal computation uses humantime parsing of String.

ConnectorState

  • Bytes are opaque - the wrapping type does not impose schema.
  • Serialization is MessagePack via rmp_serde. Compact, deterministic, well-supported in serde.
  • serialize/deserialize helpers return Option<T> and log on failure. Failures are non-fatal - design downstream code to tolerate fresh state.
  • Don't change the underlying format without coordinating with all sources.

Tests for SDK changes

  • Unit tests for any new pure function in the changed module.
  • Round-trip tests for new schemas/transforms (encode → decode == identity for JSON-equivalent payloads).
  • sdk/tests/ integration tests when the change crosses module boundaries.

Before declaring done

cargo fmt --all
cargo sort --no-format --workspace
cargo clippy -p iggy_connector_sdk --all-targets --all-features -- -D warnings
cargo test -p iggy_connector_sdk --all-features

# Rebuild all plugins to catch breaking-change leaks:
cargo build -p iggy_connector_stdout_sink -p iggy_connector_random_source
# If FFI signatures changed, also build the runtime:
cargo build -p iggy-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-sink

無料概要あり

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

  • DBへ書き込むSinkを作りたいとき
  • HTTP連携用のSinkを追加したいとき
  • リトライやバッチ処理を見直したいとき
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 のスキルをすべて見る

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