EventJournal: after #7461, a custom journal cannot decode EventLog payloads with one union codec
メンテナーはふだん 1 日以内に返信
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 55/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 活発
- 技術スタック
- typescript
- 領域
- backend
調査の方向性
Run the supplied repro with bun repro.ts, then inspect the EventJournal.write and Entry.payload contracts alongside the #7461 changeset. Determine whether the documentation, migration note, or a group decoding helper best makes the per-event payloadSchemaBinary requirement explicit, and confirm the repro no longer leaves custom journals decoding payloads with an incompatible union codec.
索引モデルが issue の本文から書いたものです。
説明
What version of Effect is running?
effect 4.0.0-rc.117 (upgrading from 4.0.0-rc.112)
What steps can reproduce the bug?
A custom EventJournal receives write({ event, primaryKey, payload }) from EventLog and must decode payload itself, for example to validate the entry or to store it in its own format. On rc.112 the payload was MessagePack, which describes itself, so a journal could decode every event in a group with one codec built from the union of the payload schemas.
#7461 removed effect/unstable/encoding/Msgpack. The obvious port, Msgpack.schema(Union) → SchemaBinary.toCodec(Union), compiles and type-checks, but it rejects every payload that EventLog writes. SchemaBinary bytes follow the layout of the codec that wrote them, and EventLog writes each payload with its own event's payloadSchemaBinary, not with a codec for the union.
Minimal repro (both versions installed side by side):
{
"type": "module",
"dependencies": {
"effect-old": "npm:[email protected]",
"effect": "4.0.0-rc.117"
}
}
import * as OldSchema from 'effect-old/Schema'
import * as OldMsgpack from 'effect-old/unstable/encoding/Msgpack'
import * as OldEventGroup from 'effect-old/unstable/eventlog/EventGroup'
import * as Schema from 'effect/Schema'
import * as SchemaBinary from 'effect/unstable/encoding/SchemaBinary'
import * as EventGroup from 'effect/unstable/eventlog/EventGroup'
const oldPayloads = [
OldSchema.Struct({ name: OldSchema.Literal('user/create'), id: OldSchema.String }),
OldSchema.Struct({ name: OldSchema.Literal('user/rename'), id: OldSchema.String, to: OldSchema.String })
] as const
const payloads = [
Schema.Struct({ name: Schema.Literal('user/create'), id: Schema.String }),
Schema.Struct({ name: Schema.Literal('user/rename'), id: Schema.String, to: Schema.String })
] as const
const OldGroup = OldEventGroup.empty
.add({ tag: 'user/create', primaryKey: (p) => p.id, payload: oldPayloads[0] })
.add({ tag: 'user/rename', primaryKey: (p) => p.id, payload: oldPayloads[1] })
const Group = EventGroup.empty
.add({ tag: 'user/create', primaryKey: (p) => p.id, payload: payloads[0] })
.add({ tag: 'user/rename', primaryKey: (p) => p.id, payload: payloads[1] })
const input = { name: 'user/rename', id: 'u1', to: 'Ada' } as const
// rc.112: EventLog writes event.payloadMsgPack bytes; one union codec decodes them.
const oldBytes = OldSchema.encodeSync(OldGroup.events['user/rename'].payloadMsgPack)(input)
console.log('rc.112 union decode:', OldSchema.decodeUnknownSync(OldMsgpack.schema(OldSchema.Union(oldPayloads)))(oldBytes))
// rc.117: EventLog writes event.payloadSchemaBinary bytes; the direct port of the same journal code fails.
const bytes = Schema.encodeSync(Group.events['user/rename'].payloadSchemaBinary)(input)
Schema.decodeUnknownSync(SchemaBinary.toCodec(Schema.Union(payloads)))(bytes)
Run it with bun repro.ts.
What is the expected behavior?
Either a journal can decode an EventLog payload without knowing which event wrote it, as on rc.112, or the API makes the per-event contract hard to miss.
What do you see instead?
rc.112 union decode: { name: "user/rename", id: "u1", to: "Ada" }
SchemaError(Missing key)
The union codec fails for every member of the union, not only for later ones. So every EventLog write through such a journal fails at runtime, and nothing in the types warns about it. The fix is to look up group.events[tag].payloadSchemaBinary for each entry, but nothing in the EventJournal docs or the #7461 changeset points to it.
Additional information
Possible fixes, from smallest to largest:
- Document on
EventJournal.writeandEntry.payloadthat the bytes are encoded with the writing event'spayloadSchemaBinary, so a reader must decode them with that same codec. - Add a migration note to the #7461 changeset:
SchemaBinary.toCodec(schema)is not a drop-in replacement forMsgpack.schema(schema)when the reader's schema differs from the writer's, for example a union reading a member's bytes. - Export a helper that decodes an entry for a group, for example
EventGroup.decodePayload(group, entry), so custom journals do not have to write their own lookup by tag.
- 主要言語
- TypeScript
- スター
- 16.7k
- フォーク
- 808
- 平均マージ
- 10時間 15分
- マージ済み PR(30日)
- 845
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
Effect-TS/effect のほかの issue
-
Let OTLP log and trace exporters leave no timer pending while idle対応中かも @effect-bot が今日担当しました。 オープン
Effect-TS/effect#10234 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
Otlp.layerFromConfig exports nothing when only OTEL_EXPORTER_OTLP_ENDPOINT is set対応中かも @effect-bot が今日担当しました。 オープン
Effect-TS/effect#10231 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
sql: give BEGIN, COMMIT, ROLLBACK and savepoint statements their own spans under sql.transaction対応中かも @effect-bot が今日担当しました。 オープン
Effect-TS/effect#10203 · コメント 1 件 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
OpenApi.fromApi (4.1.0) emits duplicate component schemas with a _1 suffix when the encoded side differs再び着手できるかも このイシューのプルリクエストはマージされずにクローズされました。 オープン
難易度 3/5 1〜2日 初心者へのやさしさ 35/100
メンテナーはふだん 1 日以内に返信
-
難易度 5/5 1週間以上 初心者へのやさしさ 35/100
メンテナーはふだん 1 日以内に返信
Effect-TS/effect の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
Northeastern-Electric-Racing/FinishLine#4660 ·
メンテナーはふだん 2 日以内に返信
-
BeOS .json missingオープン
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
mihaip/infinite-mac#475 ·
-
Let TypeScript accept an initial object in ReactiveDict対応中かも @yograj-vijay-yadav が今日担当しました。 オープンbug good first issue help wanted workshop
難易度 2/5 1〜3時間 初心者へのやさしさ 92/100
meteor/meteor#14919 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 83/100
marmelab/atomic-crm#401 ·
メンテナーはふだん 1 日以内に返信
-
account: profile
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
メンテナーはふだん 5 日以内に返信