Skip to content

fix: env var decoding for bool config fields, redis sentinel multi-node support and change fs.FS path construction#4545

Open
vsengar-79 wants to merge 6 commits into
openmeterio:mainfrom
vsengar-79:main
Open

fix: env var decoding for bool config fields, redis sentinel multi-node support and change fs.FS path construction#4545
vsengar-79 wants to merge 6 commits into
openmeterio:mainfrom
vsengar-79:main

Conversation

@vsengar-79

@vsengar-79 vsengar-79 commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Overview

Four small fixes for running OpenMeter in Kubernetes where config values arrive as environment variable strings rather than typed YAML values.

  1. app/config/viper.gobool env var decoding

Added StringToBasicTypeHookFunc() to the global DecodeHook. When config values are set via env vars or ConfigMaps, they are always strings — "true", "false", "1". Without this hook, any bool config field panics on startup with:

expected type 'bool', got unconvertible type 'string', value: 'false'

This affects fields like DEDUPE_ENABLED, NOTIFICATION_ENABLED, and any other boolean config sourced from the environment.

  1. app/config/sink.goconsumer group ID key name typo

sink.kafka.consumerGroupIdsink.kafka.consumerGroupID (capital ID to match the struct field's mapstructure tag). Fixed a little typo.

  1. pkg/redis/client.goRedis Sentinel multi-node support

The Address field now supports a comma-separated list of sentinel nodes (e.g. "sentinel1:26379,sentinel2:26379,sentinel3:26379"). Previously it was hardcoded to []string{o.Address}, which only ever used a single sentinel endpoint regardless of what was configured.

  1. tools/migrate/fs.gouse path.Join instead of filepath.Join for fs.FS path construction

filepath.Join uses the OS path separator (\ on Windows), which breaks fs.FS implementations that require forward-slash paths per the io/fs spec. Replace with path.Join which always uses /

Notes for reviewer

  • StringToBasicTypeHookFunc only activates when the target struct field is a basic type (bool, int, float64) — it has no effect on string fields or interface{} maps. Existing YAML-based configs are unaffected since YAML already deserialises native types correctly.
  • The sentinel change is backward compatible — strings.Split on a non-comma string returns a single-element slice, identical to the previous []string{o.Address} behaviour.
  • The consumer group typo fix has no migration concern — the field was silently broken before, so no existing deployment relied on the wrong default being applied.
  • The path package (always forward-slash) is used instead of filepath (OS-dependent separator) because fs.FS requires forward-slash paths on all platforms per the io/fs spec; the function parameter was renamed from path to dir to avoid shadowing the import.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Redis Sentinel configuration now accepts multiple node addresses as a comma-separated string.
  • Improvements

    • Enhanced configuration processing with automatic string-to-basic-type conversion.
    • Updated migration tool path handling to use consistent slash-based joining.
  • Bug Fixes

    • Corrected the sink Kafka consumer group default to apply to the intended configuration key.

Signed-off-by: vsengar-79 <146079793+vsengar-79@users.noreply.github.com>
Signed-off-by: vsengar-79 <146079793+vsengar-79@users.noreply.github.com>
Signed-off-by: vsengar-79 <146079793+vsengar-79@users.noreply.github.com>
Signed-off-by: vsengar-79 <146079793+vsengar-79@users.noreply.github.com>
filepath.Join uses the OS path separator (\ on Windows), which breaks fs.FS implementations that require forward-slash paths per the io/fs spec. Replace with path.Join which always uses /.

Signed-off-by: vsengar-79 <146079793+vsengar-79@users.noreply.github.com>
@vsengar-79 vsengar-79 requested a review from a team as a code owner June 21, 2026 11:26
@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Four small independent fixes: a casing typo in the sink Kafka consumer group viper key, a new mapstructure.StringToBasicTypeHookFunc() added to the decode hook chain, comma-separated address parsing for Redis Sentinel clients, and a switch from filepath to path in the migrate SourceWrapper.ReadDir.

Changes

Misc Fixes

Layer / File(s) Summary
Viper key casing fix + decode hook
app/config/sink.go, app/config/viper.go
Corrects the sink Kafka consumer group ID key from consumerGroupId to consumerGroupID so the "openmeter-sink-worker" default lands on the right key, and inserts mapstructure.StringToBasicTypeHookFunc() into the DecodeHook chain.
Redis Sentinel multi-address support
pkg/redis/client.go
Parses o.Address as a comma-separated list, trims whitespace per entry, and passes the resulting slice to redis.FailoverOptions.SentinelAddrs instead of wrapping a single address.
Migrate fs cross-platform path fix
tools/migrate/fs.go
Swaps path/filepath for path in SourceWrapper.ReadDir, uses path.Join for slash-based path construction, and renames the parameter from path to dir.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly matches the main config, Redis sentinel, and fs.FS path changes in the PR.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/redis/client.go`:
- Around line 61-68: The code splits and trims sentinel addresses but does not
filter out empty strings that can result from trailing, leading, or double
commas in the address string. After trimming each address in the sentinelAddrs
loop, filter out any entries that are empty strings. Additionally, add
validation after the loop to ensure the final sentinelAddrs slice is not empty,
and fail fast with an appropriate error message if no valid sentinel addresses
remain after filtering.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 28f3a5df-20d6-455d-bc7f-ff317c165a1e

📥 Commits

Reviewing files that changed from the base of the PR and between 5176487 and 658ad9d.

📒 Files selected for processing (4)
  • app/config/sink.go
  • app/config/viper.go
  • pkg/redis/client.go
  • tools/migrate/fs.go

Comment thread pkg/redis/client.go
@greptile-apps

greptile-apps Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Four small but meaningful bug-fixes for Kubernetes deployments where config arrives as env var strings. Covers bool coercion during viper decode, a Kafka consumer group ID key typo, Redis Sentinel multi-node address support, and cross-platform fs.FS path construction.

  • app/config/viper.go: Adds StringToBasicTypeHookFunc() to the decode hook chain so string values from env vars/ConfigMaps are automatically coerced to bool, int, and float64 target fields — preventing startup panics on fields like DEDUPE_ENABLED.
  • app/config/sink.go: Fixes the viper default key consumerGroupIdconsumerGroupID to match the ConsumerGroupID struct field tag used throughout the rest of the Kafka config.
  • pkg/redis/client.go: Parses the Address string as a comma-separated list of sentinel nodes, filters empty entries, and returns a clear error if no valid addresses remain — all backward-compatible with the prior single-address behaviour.
  • tools/migrate/fs.go: Swaps filepath.Join (OS separator) for path.Join (always /) when building fs.FS paths, fixing a Windows breakage mandated by the io/fs spec.

Confidence Score: 5/5

All four changes are targeted, backward-compatible bug fixes with no new logic paths that could regress existing behaviour.

Each change is narrowly scoped: a one-line hook addition, a key-name typo fix, an address-parsing loop with an explicit guard, and an import swap. No new abstractions, no schema changes, and the sentinel parsing is explicitly backward-compatible with single-address strings.

No files require special attention.

Important Files Changed

Filename Overview
app/config/viper.go Appends StringToBasicTypeHookFunc() to the decode hook chain so string env vars are coerced to bool/int/float64 target types without panicking on startup.
app/config/sink.go Corrects the viper default key from consumerGroupId to consumerGroupID, matching the ConsumerGroupID struct field and the key used in ConfigureKafkaConfiguration.
pkg/redis/client.go Adds comma-separated sentinel address parsing with empty-entry filtering and an explicit error when no valid addresses are found; backward-compatible with single-address configs.
tools/migrate/fs.go Replaces filepath.Join with path.Join for fs.FS path construction, fixing Windows incompatibility per the io/fs spec requirement for forward-slash-only paths.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Env var / ConfigMap string] --> B{DecodeHook chain}
    B --> C[MapDecoderHookFunc]
    C --> D[TextUnmarshallerHookFunc]
    D --> E[StringToTimeDurationHookFunc]
    E --> F["StringToSliceHookFunc(',')"]
    F --> G[StringToBasicTypeHookFunc NEW]
    G --> H{Target type?}
    H -->|bool/int/float| I[Coerced native value]
    H -->|string / other| J[Unchanged value]
    I --> K[Struct field populated]
    J --> K

    subgraph Redis Sentinel init
        L[o.Address string] --> M["strings.Split(',')"]
        M --> N[TrimSpace + filter empty]
        N --> O{len == 0?}
        O -->|yes| P[Return error]
        O -->|no| Q[redis.NewFailoverClient with sentinelAddrs]
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[Env var / ConfigMap string] --> B{DecodeHook chain}
    B --> C[MapDecoderHookFunc]
    C --> D[TextUnmarshallerHookFunc]
    D --> E[StringToTimeDurationHookFunc]
    E --> F["StringToSliceHookFunc(',')"]
    F --> G[StringToBasicTypeHookFunc NEW]
    G --> H{Target type?}
    H -->|bool/int/float| I[Coerced native value]
    H -->|string / other| J[Unchanged value]
    I --> K[Struct field populated]
    J --> K

    subgraph Redis Sentinel init
        L[o.Address string] --> M["strings.Split(',')"]
        M --> N[TrimSpace + filter empty]
        N --> O{len == 0?}
        O -->|yes| P[Return error]
        O -->|no| Q[redis.NewFailoverClient with sentinelAddrs]
    end
Loading

Reviews (2): Last reviewed commit: "Improve sentinel address parsing in Redi..." | Re-trigger Greptile

Comment thread pkg/redis/client.go Outdated
Refactor sentinel address handling to trim whitespace and validate addresses.

Signed-off-by: vsengar-79 <146079793+vsengar-79@users.noreply.github.com>
@vsengar-79 vsengar-79 changed the title fix: env var decoding for bool config fields and redis sentinel multi-node support and change fs.FS path construction fix: env var decoding for bool config fields, redis sentinel multi-node support and change fs.FS path construction Jun 27, 2026
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.

1 participant