Skip to content

Replace raw numeric time parameters with TimeSpan and DateTimeOffset#258

Merged
currantw merged 35 commits intovalkey-io:mainfrom
currantw:currantw/timespan-api-parameters
Apr 6, 2026
Merged

Replace raw numeric time parameters with TimeSpan and DateTimeOffset#258
currantw merged 35 commits intovalkey-io:mainfrom
currantw:currantw/timespan-api-parameters

Conversation

@currantw
Copy link
Copy Markdown
Collaborator

@currantw currantw commented Apr 1, 2026

Summary

Replace raw numeric types (long, double) with idiomatic .NET time types (TimeSpan, DateTimeOffset) for all time-related parameters across the public API surface. Remove incorrect Abstract-layer (SER compatibility) overloads that don't exist in StackExchange.Redis.

Issue Link

⚪ None — this addresses an API consistency gap identified during development.

Features and Behaviour Changes

GLIDE-native API signature updates

Command Before After
WaitAsync long timeout (milliseconds) TimeSpan timeout
SortedSetBlockingPopAsync double timeout (seconds) TimeSpan timeout
HashExpireAsync long seconds TimeSpan expiry
HashPExpireAsync long milliseconds (consolidated into HashExpireAsync)
HashExpireAtAsync long unixSeconds DateTimeOffset expiry
HashPExpireAtAsync long unixMilliseconds (consolidated into HashExpireAtAsync)
StreamClaimAsync long minIdleTimeInMs, long? idleTimeInMs, long? timeUnixMs TimeSpan minIdleTime, TimeSpan? idleTime, DateTimeOffset? timestamp
StreamClaimIdsOnlyAsync long minIdleTimeInMs, long? idleTimeInMs, long? timeUnixMs TimeSpan minIdleTime, TimeSpan? idleTime, DateTimeOffset? timestamp
StreamAutoClaimAsync long minIdleTimeInMs TimeSpan minIdleTime
StreamAutoClaimIdsOnlyAsync long minIdleTimeInMs TimeSpan minIdleTime
StreamPendingMessagesAsync long? minIdleTimeInMs TimeSpan? minIdleTime

Removed incorrect SER compatibility overloads

These methods were in the Abstract layer (IDatabaseAsync/Database) but do not exist in StackExchange.Redis:

Removed Method Reason
WaitAsync(long, long, CommandFlags) Not present in SER
SortedSetBlockingPopAsync(…, CommandFlags) (3 overloads) Not present in SER
HashPersistAsync(…, CommandFlags) Incorrect signature; will be re-added in #259
HashExpireAsync(…, CommandFlags) Incorrect signature; will be re-added in #259
HashPExpireAsync(…, CommandFlags) Incorrect signature; will be re-added in #259
HashExpireAtAsync(…, CommandFlags) Incorrect signature; will be re-added in #259
HashPExpireAtAsync(…, CommandFlags) Incorrect signature; will be re-added in #259
HashExpireTimeAsync(…, CommandFlags) Incorrect signature; will be re-added in #259
HashPExpireTimeAsync(…, CommandFlags) Incorrect signature; will be re-added in #259
HashTtlAsync(…, CommandFlags) Incorrect signature; will be re-added in #259
HashPTtlAsync(…, CommandFlags) Incorrect signature; will be re-added in #259
StreamPendingMessagesAsync(…, minIdleTimeInMs, CommandFlags) Not present in SER
StreamClaimAsync(…, idleTimeInMs, timeUnixMs, …, CommandFlags) Not present in SER
StreamClaimIdsOnlyAsync(…, idleTimeInMs, timeUnixMs, …, CommandFlags) Not present in SER

Removed misleading overload

Removed Method Reason
SortedSetBlockingPopAsync(ValkeyKey, long count, Order, double) BZPOPMIN/BZPOPMAX do not support COUNT at the protocol level; the implementation was already throwing for count != 1

Implementation

  • Numeric conversion is deferred to the Request builder layer (Internals/Request.*.cs). BaseClient passes TimeSpan/DateTimeOffset through without conversion.
  • Hash expire commands always use millisecond-precision Valkey commands (HPEXPIRE, HPEXPIREAT) since they are functionally identical to their seconds-precision counterparts, avoiding the need for precision-based command selection.
  • Simplified unnecessary ToGlideString() calls for string literals in Request.StreamCommands.cs by relying on implicit conversion.
  • Pipeline/batch interfaces (IBatch*Commands, BaseBatch.*Commands, Batch, ClusterBatch) updated to match the GLIDE-native API signatures.
  • XML doc comments updated to remove unit references and use idiomatic examples.

Limitations

⚪ None

Testing

  • Updated all unit test call sites in CommandTests.cs and SortedSetCommandTests.cs to use TimeSpan/DateTimeOffset parameters.
  • Updated all integration test call sites in GenericCommandTests.cs, SortedSetCommandTests.cs, HashCommandTests.cs, StreamCommandTests.cs, StreamConsumerGroupTests.cs, and BatchTestUtils*.cs.
  • Removed tests for eliminated overloads.

Related Issues

Checklist

  • This Pull Request is related to one issue.
  • Commit message has a detailed description of what changed and why.
  • Tests are added or updated and all checks pass.
  • CHANGELOG.md, README.md, DEVELOPER.md, and other documentation files are updated.
  • Destination branch is correct - main or release
  • Create merge commit if merging release branch into main, squash otherwise.

currantw added 6 commits April 1, 2026 14:45
Signed-off-by: currantw <taylor.curran@improving.com>
Replace raw long milliseconds parameter with TimeSpan in WaitAsync across
interface, BaseClient, Request builder, Pipeline batch, and Abstract layer.
Numeric conversion deferred to Request builder via (long)timeout.TotalMilliseconds.

Signed-off-by: currantw <taylor.curran@improving.com>
…to TimeSpan

Replace raw double seconds parameter with TimeSpan in all 3
SortedSetBlockingPopAsync overloads across interface, BaseClient, Request
builder, Pipeline batch, and Abstract layer. Numeric conversion deferred to
Request builder via timeout.TotalSeconds.

Signed-off-by: currantw <taylor.curran@improving.com>
…imeOffset

Consolidate HashExpireAsync/HashPExpireAsync into single HashExpireAsync(TimeSpan)
and HashExpireAtAsync/HashPExpireAtAsync into single HashExpireAtAsync(DateTimeOffset).
Request builder auto-selects HEXPIRE vs HPEXPIRE and HEXPIREAT vs HPEXPIREAT
based on precision (milliseconds % 1000), mirroring the KeyExpireAsync pattern.

Signed-off-by: currantw <taylor.curran@improving.com>
…teTimeOffset

Replace long minIdleTimeInMs/idleTimeInMs with TimeSpan and long timeUnixMs
with DateTimeOffset across StreamClaimAsync, StreamClaimIdsOnlyAsync,
StreamAutoClaimAsync, StreamAutoClaimIdsOnlyAsync, and StreamPendingMessagesAsync.
Drop InMs parameter name suffixes. Numeric conversion deferred to Request builder.

Signed-off-by: currantw <taylor.curran@improving.com>
…PI changes

Update all test call sites to use TimeSpan/DateTimeOffset instead of raw
numeric types. Covers SortedSet unit tests, SortedSet/Generic/Hash/Stream
integration tests, batch test utils, and CommandTests unit test assertions.

Signed-off-by: currantw <taylor.curran@improving.com>
@currantw currantw self-assigned this Apr 1, 2026
@currantw currantw changed the title fix: replace raw numeric time parameters with TimeSpan and DateTimeOffset Replace raw numeric time parameters with TimeSpan and DateTimeOffset Apr 1, 2026
currantw added 3 commits April 1, 2026 16:04
… conversions

Extract intermediary variables (minIdleTime, idleTime, timestamp) in
Database.StreamCommands.cs to improve readability of nullable time
parameter conversions in StreamPendingMessagesAsync, StreamClaimAsync,
and StreamClaimIdsOnlyAsync.

Signed-off-by: currantw <taylor.curran@improving.com>
…ility.

Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
currantw added 2 commits April 1, 2026 16:26
…hExpireAsync, HashPExpireAsync, HashExpireAtAsync, HashPExpireAtAsync, HashExpireTimeAsync, HashPExpireTimeAsync, HashTtlAsync, HashPTtlAsync) from both IDatabaseAsync.HashCommands.cs and Database.HashCommands.cs. These will be re-added with correct SER-compatible signatures in issue valkey-io#259.

Signed-off-by: currantw <taylor.curran@improving.com>
…iration

Remove precision-based command selection (milliseconds % 1000 check) from
HashExpireAsync and HashExpireAtAsync request builders. Always use
HPEXPIRE and HPEXPIREAT under the hood since they are functionally
identical to their seconds-precision counterparts. Clean up XML doc
comments and remove duplicate unit tests.

Signed-off-by: currantw <taylor.curran@improving.com>
…bility layer

These methods do not exist in StackExchange.Redis and were incorrectly
placed in the Abstract compatibility layer.

Signed-off-by: currantw <taylor.curran@improving.com>
currantw added 2 commits April 1, 2026 17:15
Add param doc overrides for minIdleTimeInMs, idleTimeInMs, and timeUnixMs
in IDatabaseAsync.StreamCommands.cs to correctly describe the long-based
parameters instead of inheriting TimeSpan/DateTimeOffset descriptions
from the GLIDE-native methods.

Signed-off-by: currantw <taylor.curran@improving.com>
… param docs

Remove StreamPendingMessagesAsync (with minIdleTimeInMs), StreamClaimAsync,
and StreamClaimIdsOnlyAsync extended overloads from the Abstract layer as
they do not exist in StackExchange.Redis. Update remaining param docs to
match SER descriptions.

Signed-off-by: currantw <taylor.curran@improving.com>
currantw added 5 commits April 2, 2026 07:47
Signed-off-by: currantw <taylor.curran@improving.com>
…m documentation

Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
currantw added 2 commits April 2, 2026 08:35
…ey count overload

Remove SortedSetBlockingPopAsync(ValkeyKey, long, Order, TimeSpan) which
accepted a count parameter but silently ignored it. BZPOPMIN/BZPOPMAX do
not support a COUNT argument at the protocol level, so this overload could
never honor count > 1. The multi-key blocking variant (BZMPOP) correctly
supports count and remains unchanged.

Signed-off-by: currantw <taylor.curran@improving.com>
…param docs

Signed-off-by: currantw <taylor.curran@improving.com>
@currantw currantw force-pushed the currantw/timespan-api-parameters branch from 77aaa04 to 3b461ab Compare April 2, 2026 15:38
Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates Valkey GLIDE’s public API surface to use idiomatic .NET time types (TimeSpan, DateTimeOffset) instead of raw numeric time parameters, and propagates those signature changes through request building, pipeline/batch APIs, Abstract (SER-compat) APIs, and tests.

Changes:

  • Replaced numeric timeout/idle/expiry parameters with TimeSpan and DateTimeOffset across commands (e.g., WAIT, blocking ZSET pop, stream claim/autoclaim, hash field expiry).
  • Consolidated hash field expiration APIs to millisecond-precision commands (HPEXPIRE, HPEXPIREAT) and removed several Abstract-layer SER-compat overloads that were incorrect/not present in SER.
  • Updated unit/integration tests plus pipeline/batch interfaces and implementations to match the new signatures.

Reviewed changes

Copilot reviewed 41 out of 41 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
tests/Valkey.Glide.UnitTests/SortedSetCommandTests.cs Updated SortedSet blocking pop tests to use TimeSpan timeouts and removed tests for deleted overloads.
tests/Valkey.Glide.UnitTests/CommandTests.cs Updated WAIT/hash expire/stream tests to use TimeSpan/DateTimeOffset and adjusted expected args.
tests/Valkey.Glide.IntegrationTests/StreamConsumerGroupTests.cs Updated Stream claim/autoclaim/pending calls to TimeSpan min-idle / idle parameters.
tests/Valkey.Glide.IntegrationTests/StreamCommandTests.cs Updated Stream claim/autoclaim error-path tests to pass TimeSpan.
tests/Valkey.Glide.IntegrationTests/SortedSetCommandTests.cs Updated blocking timeout type to TimeSpan and adapted tests to the remaining blocking-pop overloads.
tests/Valkey.Glide.IntegrationTests/HashCommandTests.cs Updated hash expire/expire-at tests to use TimeSpan and DateTimeOffset.
tests/Valkey.Glide.IntegrationTests/GenericCommandTests.cs Updated WAIT tests to use TimeSpan and kept negative-timeout validation coverage.
tests/Valkey.Glide.IntegrationTests/BatchTestUtils.StreamTests.cs Updated batch StreamClaim usage to TimeSpan.
tests/Valkey.Glide.IntegrationTests/BatchTestUtils.cs Updated batch WAIT/ZSET blocking pop/hash expire call sites to TimeSpan and aligned batch API usage.
sources/Valkey.Glide/Pipeline/IBatchStreamCommands.cs Updated batch stream command signatures/docs to TimeSpan/DateTimeOffset.
sources/Valkey.Glide/Pipeline/IBatchSortedSetCommands.cs Updated batch sorted set blocking-pop signatures to TimeSpan and removed the single-key count overload.
sources/Valkey.Glide/Pipeline/IBatchHashCommands.cs Consolidated batch hash expire/expire-at signatures to TimeSpan/DateTimeOffset.
sources/Valkey.Glide/Pipeline/IBatchGenericCommands.cs Updated batch WAIT signature to accept TimeSpan.
sources/Valkey.Glide/Pipeline/ClusterBatch.cs Updated explicit interface implementations to new stream time parameter types.
sources/Valkey.Glide/Pipeline/Batch.cs Updated explicit interface implementations to new stream time parameter types.
sources/Valkey.Glide/Pipeline/BaseBatch.StreamCommands.cs Updated batch stream command wrappers to pass through TimeSpan/DateTimeOffset.
sources/Valkey.Glide/Pipeline/BaseBatch.SortedSetCommands.cs Updated batch sorted set blocking-pop wrappers and removed obsolete overload wiring.
sources/Valkey.Glide/Pipeline/BaseBatch.HashCommands.cs Consolidated hash expire/expire-at wrappers to TimeSpan/DateTimeOffset.
sources/Valkey.Glide/Pipeline/BaseBatch.GenericCommands.cs Updated batch WAIT wrapper signature to TimeSpan.
sources/Valkey.Glide/Internals/Request.String.cs Minor request parsing change using string literals relying on GlideString implicit conversion.
sources/Valkey.Glide/Internals/Request.StreamCommands.cs Updated stream request builders to accept TimeSpan/DateTimeOffset and convert to ms.
sources/Valkey.Glide/Internals/Request.SortedSetCommands.cs Updated sorted set blocking-pop request builders to accept TimeSpan and serialize seconds.
sources/Valkey.Glide/Internals/Request.HashCommands.cs Consolidated hash expire/expire-at request builders to accept TimeSpan/DateTimeOffset and always use ms-precision requests.
sources/Valkey.Glide/Internals/Request.GenericCommands.cs Updated WAIT request builder to accept TimeSpan and serialize milliseconds.
sources/Valkey.Glide/Commands/IStreamCommands.cs Updated stream command interfaces/docs to use TimeSpan/DateTimeOffset for time values.
sources/Valkey.Glide/Commands/ISortedSetCommands.cs Updated sorted set blocking-pop timeout type to TimeSpan and removed a count overload.
sources/Valkey.Glide/Commands/IHashCommands.cs Consolidated hash field expiration interface/docs to TimeSpan/DateTimeOffset and removed older numeric overload docs.
sources/Valkey.Glide/Commands/IGenericBaseCommands.cs Updated WAIT interface/docs to use TimeSpan.
sources/Valkey.Glide/BaseClient.StreamCommands.cs Updated BaseClient stream methods to accept TimeSpan/DateTimeOffset.
sources/Valkey.Glide/BaseClient.SortedSetCommands.cs Updated BaseClient sorted set blocking pop to TimeSpan and removed the count overload implementation.
sources/Valkey.Glide/BaseClient.HashCommands.cs Consolidated BaseClient hash expire/expire-at to TimeSpan/DateTimeOffset.
sources/Valkey.Glide/BaseClient.GenericCommands.cs Updated BaseClient WAIT to accept TimeSpan.
sources/Valkey.Glide/Abstract/IDatabaseAsync.StreamCommands.cs Partially updated stream docs/refs for time changes and removed an overload; signatures still use long ms for some methods.
sources/Valkey.Glide/Abstract/IDatabaseAsync.SortedSetCommands.cs Removed SortedSetBlockingPopAsync Abstract overloads (SER mismatch).
sources/Valkey.Glide/Abstract/IDatabaseAsync.HashCommands.cs Removed hash field expiration-related Abstract methods with incorrect SER signatures.
sources/Valkey.Glide/Abstract/IDatabaseAsync.GenericCommands.cs Removed WAIT Abstract overload with flags (SER mismatch).
sources/Valkey.Glide/Abstract/Database.StreamCommands.cs Updated Abstract stream wrappers to convert ms long inputs into TimeSpan for GLIDE-native calls.
sources/Valkey.Glide/Abstract/Database.SortedSetCommands.cs Removed corresponding Abstract sorted set blocking-pop overload implementations.
sources/Valkey.Glide/Abstract/Database.HashCommands.cs Removed corresponding Abstract hash field expire-related overload implementations.
sources/Valkey.Glide/Abstract/Database.GenericCommands.cs Removed corresponding Abstract WAIT overload implementation.
SECURITY.md Reformatted contact emails in markdown.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

currantw added 5 commits April 2, 2026 13:39
… into currantw/timespan-api-parameters

Signed-off-by: currantw <taylor.curran@improving.com>
…on issues

- Add ToMilliseconds and ToSeconds helpers to Request class that convert
  TimeSpan values via Ticks division instead of TotalMilliseconds/TotalSeconds
  (which return doubles and can produce fractional or imprecise values).
- Replace all TotalMilliseconds, TotalSeconds, and (long)TotalMilliseconds
  casts across Request.*.cs files with the new helpers.
- Simplify KeyExpireAsync to always use PExpire/PExpireAt (millisecond
  precision), removing unnecessary seconds-vs-milliseconds branching.

Addresses review feedback on PR valkey-io#258.

Signed-off-by: currantw <taylor.curran@improving.com>
The field is a TimeSpan, so the 'Secs' suffix is misleading. Rename to
the unit-agnostic 'BlockingTimeout'.

Signed-off-by: currantw <taylor.curran@improving.com>
- Update SortedSetCommandTests comment from 'blocking pop with multiple
  elements' to 'single-key blocking pop with next element' to match the
  single-element overload being called.
- Update BatchTestUtils description from 'HashPExpire(...)' to
  'HashExpire(...)' to match the renamed API method.

Addresses review feedback on PR valkey-io#258.

Signed-off-by: currantw <taylor.curran@improving.com>
Use inheritdoc path filter to exclude the inherited minIdleTime param
doc (which describes a TimeSpan) so it doesn't conflict with the local
minIdleTimeInMs param doc (which describes a long milliseconds value).

Addresses review feedback on PR valkey-io#258.

Signed-off-by: currantw <taylor.curran@improving.com>
@currantw currantw requested review from alexr-bq and jeremyprime April 2, 2026 21:52
currantw added 3 commits April 2, 2026 18:24
… into currantw/timespan-api-parameters

Signed-off-by: currantw <taylor.curran@improving.com>
…timeouts

BZPOPMIN/BZPOPMAX accept fractional second timeouts at the protocol level.
The long return type truncated sub-second values, causing e.g.
TimeSpan.FromSeconds(0.1) to become 0 (block indefinitely).

Signed-off-by: currantw <taylor.curran@improving.com>
… use PX

- PubSub blocking Request methods now accept TimeSpan instead of uint,
  using ToMilliseconds() internally. Callers no longer cast manually.
- GETEX StringGetSetExpiry uses PX (milliseconds) instead of EX (seconds)
  to avoid sending fractional values after ToSeconds was changed to double.
- Fix pre-existing KeyExpire test expectations (PEXPIRE/PEXPIREAT).

Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
currantw added 2 commits April 3, 2026 14:52
Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
@currantw currantw merged commit a29be08 into valkey-io:main Apr 6, 2026
20 of 22 checks passed
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.

4 participants