Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default values on initialization #119

Merged
merged 39 commits into from
Aug 6, 2023

Conversation

lewispb
Copy link
Contributor

@lewispb lewispb commented Jul 8, 2023

I built upon what was started in #89 but attempted a simpler implementation, only setting default values upon type initialization.

Closes #66 and #89

Almost all the same tests pass, with one or two minor differences.

Todo

tleish and others added 29 commits June 20, 2022 10:03
…tialize

* origin/main: (22 commits)
  Add kredis_ordered_set for OrderedSet usage in models
  Add a development console
  Bump version for 1.5.0
  Fix ordered set prepend bug (rails#115)
  Unique list with sorted set (rails#114)
  Eliminating Ruby Warnings (rails#112)
  CI against Redis 7, Ruby 3.1, and Ruby 3.2 (rails#113)
  Bump version for 1.4.0
  Update nokogiri for compatibility
  Revert "Improved version of UniqueList: OrderedSet (rails#76)" (rails#111)
  Add `last` to lists (rails#97)
  Improved version of UniqueList: OrderedSet (rails#76)
  Return Time objects instead of deprecated DateTime (rails#106)
  Fix possible deserialization of untrusted data
  Typecast return of Set#take (rails#105)
  Declare Active Model dependency (rails#107)
  Address LogSubscriber deprecation (rails#98)
  Account for time zones in DateTime serializations (rails#102)
  Add sample to set (rails#100)
  Bump version for 1.3.0
  ...
@lewispb lewispb mentioned this pull request Jul 8, 2023
@lewispb lewispb force-pushed the default-values-on-initialize branch from efa429b to 6faf4d0 Compare July 8, 2023 14:03
* main:
  Run rubocop autocorrect
  Set up RuboCop with CI
  Make boolean storage more efficient
  Support line filtering in tests
  Update Readme on local development and debugging
  Set up ruby/debug in place of byebug for dev and test
@dhh
Copy link
Member

dhh commented Jul 24, 2023

I like this a lot. Nice simplification 👍

@dhh dhh requested a review from jeremy July 24, 2023 12:02
Copy link
Member

@jeremy jeremy left a comment

Choose a reason for hiding this comment

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

Enum is a bit of an oddball re. defaults out of the enumerated set and nil defaults in particular. From HEY:

kredis_enum :status, values: %w[ waiting confirmed ], default: nil, key: …

Defaults out of the enumerated set should probably be considered a bug, with a special case for default: nil behaving how an optional: true argument would.

lib/kredis/default_values.rb Outdated Show resolved Hide resolved
lib/kredis/types/scalar.rb Outdated Show resolved Hide resolved
lib/kredis/attributes.rb Show resolved Hide resolved
lib/kredis/default_values.rb Outdated Show resolved Hide resolved
lib/kredis/types/enum.rb Show resolved Hide resolved
test/types/enum_test.rb Show resolved Hide resolved
@lewispb
Copy link
Contributor Author

lewispb commented Aug 2, 2023

Defaults out of the enumerated set should probably be considered a bug, with a special case for nil

Thanks @jeremy, agree, and updated to raise an error in that case.

@lewispb lewispb requested a review from jeremy August 2, 2023 12:07
@dhh dhh merged commit cc15c2f into rails:main Aug 6, 2023
17 checks passed
@lewispb lewispb deleted the default-values-on-initialize branch August 6, 2023 10:02
write the specified default value.

This means that using default values in a typical Rails app additional Redis calls (WATCH, EXISTS, UNWATCH) will be
executed for each Kredis attribute with a default value read or written during a request.
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this occur every request, or only when a value does not exist?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the context of a Rails web request, as the Kredis object is initialized, the key is checked with WATCH, EXISTS, UNWATCH once, but then subsequent operations within the request do not incur any Redis command overhead. If no default value is specified, no additional Redis command overhead is incurred at all.

Copy link
Contributor

Choose a reason for hiding this comment

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

To clarify:

Scenario 1: Default NOT defined

(no additional overhead)

Scenario 2: Default defined, value NOT exists

WATCH, EXISTS, UNWATCH

Scenario 3: Default defined, value exists

(no additional overhead?)

Copy link
Contributor Author

@lewispb lewispb Aug 7, 2023

Choose a reason for hiding this comment

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

Actually, it's:

Scenario 1: Default NOT defined

(no additional overhead)

Scenario 2: Default defined, value NOT exists

WATCH, EXISTS, write default (depending on type), UNWATCH

Scenario 3: Default defined, value exists

WATCH, EXISTS, UNWATCH

Copy link
Contributor

Choose a reason for hiding this comment

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

It seems a more efficient approach would be to only add extra overhead of default is defined AND value doesn't exist. In other words:

  1. Get Value
  2. Value doesn't exist
  3. Execute Default Logic

This avoids extra overhead if the value has been set already.

Copy link
Contributor Author

@lewispb lewispb Aug 8, 2023

Choose a reason for hiding this comment

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

I agree @tleish. That's exactly what we do here, but with the added WATCH / UNWATCH.

To illustrate the problem that the WATCH / UNWATCH solves check this test case:

test "concurrent initialization with default" do
5.times.map do
Thread.new do
Kredis.counter("mycounter", default: 5).increment
end
end.each(&:join)
assert_equal 10, Kredis.counter("mycounter").value
end

Without the WATCH / UNWATCH, the value existing check is prone to a race condition.

@nzwsch
Copy link

nzwsch commented Oct 14, 2023

I noticed that the default value cannot be set in kredis_integer in the current release version 1.5.0.

Failure/Error: kredis_integer :foo, default: 0

ArgumentError:
  unknown keyword: :default

When will kredis be released with this PR?

@dhh
Copy link
Member

dhh commented Oct 19, 2023

1.6.0 released 👍

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

Successfully merging this pull request may close these issues.

Default proc if empty
5 participants