Skip to content

Upgrade aliyun-datahub-sdk-go to v1.2.0 and switch to Producer API - #223

Merged
bruceding merged 5 commits into
masterfrom
features/upgrade-datahub-sdk
Aug 4, 2026
Merged

Upgrade aliyun-datahub-sdk-go to v1.2.0 and switch to Producer API#223
bruceding merged 5 commits into
masterfrom
features/upgrade-datahub-sdk

Conversation

@bruceding

Copy link
Copy Markdown
Collaborator

Background

In production we hit a nil pointer dereference panic inside the DataHub SDK v1.1.4 during feature log reporting, which crashed the whole process:

panic: runtime error: invalid memory address or nil pointer dereference
github.com/aliyun/aliyun-datahub-sdk-go/datahub.(*topicSchemaCacheImpl).getVersionIdBySchema
    datahub/schemaclient.go
...
github.com/alibaba/pairec/v2/datasource/datahub.(*Datahub).SendMessage

Root cause: in v1.1.4, when the lazy schema cache initialization fails (e.g. a transient GetTopic error), the broken cache (topicResult == nil) is still registered and getVersionIdBySchema dereferences tsc.topicResult without a nil check. The refresh window is also locked for 5 minutes, so every write during that window panics.

Changes

1. Upgrade SDK v1.1.4 -> v1.2.0

v1.2.0 fixes the root cause: schema cache getters return errors instead of panicking, a cache that failed to initialize is no longer registered, and failed refreshes retry after 1s instead of 5min.

2. Refactor datasource/datahub to the recommended Producer API

Switch from raw PutRecordsByShard with hand-written shard management to Producer:

  • Producer.Init() fails fast on init error instead of leaving a broken schema cache behind
  • shard selection (round-robin), sealed shard recovery and retryable error handling (network / limit exceeded) are managed by the producer internally
  • fetch the latest topic schema via producer.GetSchema() on each send, with the schema cached at Init as fallback, so schema evolution no longer breaks writes
  • log SetValueByName errors instead of silently dropping fields
  • remove the loopListShards goroutine and the unsynchronized d.shards / d.active fields which caused data races

The sync-log fallback on send failure keeps unchanged, and all public interfaces (NewDatahub / Init / GetDatahub / SendMessage / Shards / Stop / StopLoopListShards) keep their signatures, so all callers (feature_log, callback service, feature consistency job, embedding service, debug service) are unaffected.

Behavior changes

  • If the topic has no active shard, Init() now fails fast (previously the service started but writes were dropped with an error log).
  • Compression type for writes is now negotiated from the server-side topic config by the producer; the compressorType config still applies to the admin client used for topic creation.

Verification

  • go build ./..., go vet and go test ./datasource/datahub/... pass
  • gofmt clean

The new version fixes a nil pointer dereference panic in
topicSchemaCacheImpl.getVersionIdBySchema when schema cache
initialization fails (e.g. transient GetTopic error), which
crashed the whole process during feature log reporting.
Switch from raw PutRecordsByShard with hand-written shard
management to the recommended Producer API:

- Producer.Init() fails fast on init error instead of leaving
  a broken schema cache behind
- shard selection, sealed shard recovery and retryable error
  handling (network/limit exceeded) are managed by producer
- fetch latest topic schema via producer.GetSchema() with the
  schema cached at Init as fallback
- log SetValueByName errors instead of silently dropping them
- remove loopListShards goroutine and unsynchronized d.shards /
  d.active fields which caused data races

Sync log fallback on send failure keeps unchanged.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

@bruceding
bruceding requested a review from symphony09 July 29, 2026 01:32
Init() has two network failure points(producer.Init and GetSchema),
when it fails the caller may still hold a Datahub whose producer and
syncLog are nil. Calling SendMessage on such instance panicked on the
nil producer, and the sync log fallback panicked again on nil syncLog.

Feature log is sent from a bare goroutine, so this panic could not be
recovered by the upper layer and crashed the whole process. The old
implementation degraded safely by returning on empty shard list, so
restore that behavior:

- guard producer/syncLog with nil checks and degrade with an error log
- extract writeSyncLog to share the guarded sync log fallback
- do not register a half initialized instance in feature consistency
  job service, so the existing nil check can take effect

Add a regression test that reproduces the panic without the guards.
@bruceding
bruceding merged commit fb7f14c into master Aug 4, 2026
3 checks passed
@bruceding
bruceding deleted the features/upgrade-datahub-sdk branch August 4, 2026 09:57

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants