Skip to content

Upgrade to Rack 3 #33

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

Closed
wants to merge 36 commits into from
Closed

Upgrade to Rack 3 #33

wants to merge 36 commits into from

Conversation

ryokdy
Copy link

@ryokdy ryokdy commented Nov 24, 2023

  • Upgrade to Rack 3 and Rack::Session v2.0 Upgrade to Rack 3 #28
  • Inherit ActionDispatch::Session::AbstractSecureStore instead of Rack::Session::Abstract::Persisted
  • Remove the pessimistic locking strategy due to performance issue. It is complicated and consistency-read option is enough to solve the concurrency issues. Please implement if someone needs it.
  • Use DynamoDB local for integration test.

Replaced the generate_sid function with the default ActionDispatch::Session#generate_sid instead of the original function. Existing sessions associated with older versions of the sid will be available after upgrading the gem.
Newly created sids are hashed and stored in the database.

David Massad and others added 26 commits April 18, 2017 18:43
# Conflicts:
#	aws-sessionstore-dynamodb.gemspec
#	lib/aws/session_store/dynamo_db/locking/base.rb
#	lib/aws/session_store/dynamo_db/locking/null.rb
@mullermp mullermp added the pr/needs-review This PR needs a review from a Member. label Nov 24, 2023
@mullermp
Copy link
Contributor

Thanks for opening a PR. I will be able to review this more thoroughly soon.

Using standard generate_sid function of ActionDispatch::Session instead of the original generate_sid, existing sessions will no longer be available after upgrading the gem. The SID is hashed and stored in the database.

Do you have a recommendation for customers on how to handle this? We should also document this behavior in the changelog.

Copy link
Contributor

@mullermp mullermp left a comment

Choose a reason for hiding this comment

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

This is an interesting PR. Thanks for opening a pull request. I can talk this over with the team.

@@ -101,7 +101,7 @@ def table_opts(config)
# @api private
def oldest_date(sec)
hash = {}
hash[:attribute_value_list] = [:n => "#{((Time.now - sec).to_f)}"]
hash[:attribute_value_list] = [(Time.now - sec).to_f]
Copy link
Contributor

Choose a reason for hiding this comment

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

This might not work, I think it depends on if the SDK is configured with "simple_attributes" - I believe it defaults to true in the SDK.

Copy link
Author

Choose a reason for hiding this comment

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

The current version of the gem already does not work without the simple_attributes plugin. I have aligned coding style.
This is a testing result for the current version when I turned of the plugin.

     Failure/Error: @config.dynamo_db_client.update_item(save_opts)

     ArgumentError:
       parameter validator found 5 errors:
         - expected params[:key]["session_id"] to be a hash, got class String instead.
         - expected params[:attribute_updates]["updated_at"][:value] to be a hash, got class String instead.
         - expected params[:attribute_updates]["data"][:value] to be a hash, got class String instead.
         - expected params[:attribute_updates]["created_at"][:value] to be a hash, got class String instead.
         - expected params[:attribute_updates]["expire_at"][:value] to be a hash, got class Integer instead.
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/aws-sdk-core-3.186.0/lib/aws-sdk-core/param_validator.rb:35:in `validate!'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/aws-sdk-core-3.186.0/lib/aws-sdk-core/param_validator.rb:15:in `validate!'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/aws-sdk-core-3.186.0/lib/aws-sdk-core/plugins/param_validator.rb:25:in `call'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/aws-sdk-core-3.186.0/lib/seahorse/client/plugins/raise_response_errors.rb:16:in `call'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/aws-sdk-core-3.186.0/lib/aws-sdk-core/plugins/checksum_algorithm.rb:111:in `call'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/aws-sdk-core-3.186.0/lib/aws-sdk-core/plugins/jsonvalue_converter.rb:16:in `call'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/aws-sdk-core-3.186.0/lib/aws-sdk-core/plugins/idempotency_token.rb:19:in `call'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/aws-sdk-core-3.186.0/lib/aws-sdk-core/plugins/param_converter.rb:26:in `call'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/aws-sdk-core-3.186.0/lib/seahorse/client/plugins/request_callback.rb:89:in `call'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/aws-sdk-core-3.186.0/lib/aws-sdk-core/plugins/response_paging.rb:12:in `call'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/aws-sdk-core-3.186.0/lib/seahorse/client/plugins/response_target.rb:24:in `call'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/aws-sdk-core-3.186.0/lib/seahorse/client/request.rb:72:in `send_request'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/aws-sdk-dynamodb-1.96.0/lib/aws-sdk-dynamodb/client.rb:7248:in `update_item'
     # ./lib/aws/session_store/dynamo_db/locking/base.rb:17:in `block in set_session_data'
     # ./lib/aws/session_store/dynamo_db/locking/base.rb:44:in `handle_error'
     # ./lib/aws/session_store/dynamo_db/locking/base.rb:15:in `set_session_data'
     # ./lib/aws/session_store/dynamo_db/rack_middleware.rb:75:in `write_session'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/rack-2.2.7/lib/rack/session/abstract/id.rb:388:in `commit_session'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/rack-2.2.7/lib/rack/session/abstract/id.rb:268:in `context'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/rack-2.2.7/lib/rack/session/abstract/id.rb:260:in `call'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/rack-test-2.1.0/lib/rack/test.rb:360:in `process_request'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/rack-test-2.1.0/lib/rack/test.rb:163:in `custom_request'
     # /Users/ryo/.rvm/gems/ruby-3.1.1/gems/rack-test-2.1.0/lib/rack/test.rb:112:in `get'
     # ./spec/aws/session_store/dynamo_db/rack_middleware_database_spec.rb:83:in `block (3 levels) in <module:DynamoDB>'

Copy link
Contributor

Choose a reason for hiding this comment

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

Worth adding a check for invalid client configuration during initialization?

(@mullermp - should we also update the metrics/user agent info?)

Copy link
Author

Choose a reason for hiding this comment

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

Worth adding a check for invalid client configuration during initialization?

It's worth considering. It might be better to make it a separate issue because it is not caused by this PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think assuming that it defaults to true is fine.

@@ -13,8 +13,14 @@ def set_session_data(env, sid, session, options = {})
return false if session.empty?
packed_session = pack_data(session)
handle_error(env) do
save_opts = update_opts(env, sid, packed_session, options)
@config.dynamo_db_client.update_item(save_opts)
if env['dynamo_db.new_session']
Copy link
Contributor

Choose a reason for hiding this comment

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

If we're removing pessimistic locking, does base/null locking as classes even make sense? We can possibly refactor away anything related to locking.

Copy link
Author

Choose a reason for hiding this comment

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

I don't think I need that feature, but others might. I cannot make the decision, but I don't have much time to implement and test for the feature. Please rename files to a suitable names if we could remove the feature.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's fine to remove pessimistic locking. I am saying that locking/base and locking/null are no longer relevant (because locking is being removed entirely) and we can probably delete these classes and put the logic into rack_middleware or some other new class.

@ryokdy
Copy link
Author

ryokdy commented Nov 29, 2023

Do you have a recommendation for customers on how to handle this? We should also document this behavior in the changelog.

I added support for the legacy format sid. Sessions related to older versions of the sid will be available after upgrading.
336c2d5
8cbf185

Copy link
Contributor

@alextwoods alextwoods left a comment

Choose a reason for hiding this comment

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

Thanks for submitting this - looks good overall and I think Its reasonable to remove the pessimistic locking strategy in an MV bump.

@@ -23,7 +23,7 @@ Run the session store as a Rack middleware in the following way:
use Aws::SessionStore::DynamoDB::RackMiddleware.new(options)
run SomeRackApp

Note that `:secret_key` is a mandatory configuration option that must be set.
Note that `:secret_key` is a configuration option that is used for the older version.
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the "older version" (may help users down the road to be more specific).

Copy link
Author

Choose a reason for hiding this comment

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

I'd appreciate it if someone else could revise the README and other texts because I'm not very good at English and I might make misunderstandings. Sorry.

Copy link
Contributor

Choose a reason for hiding this comment

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

No worries~! I can do that for you when we're done.

@@ -23,7 +23,13 @@ module DynamoDB
describe Table do
context 'Mock Table Methods Tests', integration: true do
let(:table_name) { "sessionstore-integration-test-#{Time.now.to_i}" }
let(:options) { { table_name: table_name } }
let(:dynamo_db_client) {
options = {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: probably don't need a hash for this and can just initialize client

Copy link
Author

Choose a reason for hiding this comment

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

You mean like this?

Aws::DynamoDB::Client.new(endpoint: 'http://localhost:8000')

let(:options) { { table_name: table_name } }
let(:dynamo_db_client) {
options = {
endpoint: 'http://localhost:8000'
Copy link
Contributor

Choose a reason for hiding this comment

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

We should add a section in the README mentioning the use of dynamodb local for integ testing.

@@ -101,7 +101,7 @@ def table_opts(config)
# @api private
def oldest_date(sec)
hash = {}
hash[:attribute_value_list] = [:n => "#{((Time.now - sec).to_f)}"]
hash[:attribute_value_list] = [(Time.now - sec).to_f]
Copy link
Contributor

Choose a reason for hiding this comment

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

Worth adding a check for invalid client configuration during initialization?

(@mullermp - should we also update the metrics/user agent info?)

@mullermp
Copy link
Contributor

mullermp commented Dec 4, 2023

Added comments, sorry for the late reply! I will try my best to keep up with this, but I will be traveling this week.

@mullermp
Copy link
Contributor

I extracted out the minimum rack 3 upgrade here: #34. I think most of these other changes make sense in a major version bump - but for now, I think we need rack 3 available in a minor version.

@mullermp
Copy link
Contributor

I've merged and released #34 to upgrade to Rack 3. Other discussions about using locking and using ActionDispatch for a session store are needed, and major rework of this PR is needed.

From this package's POV, I think we should NOT depend on ActionDispatch (specific to rails) - this gem is intended for all rack applications, not just rails applications. I do think we can remove locking in a MV bump.

@mullermp mullermp added pr/do-not-merge This PR should not be merged at this time. and removed pr/needs-review This PR needs a review from a Member. labels Jan 25, 2024
@mullermp mullermp mentioned this pull request Oct 20, 2024
@mullermp
Copy link
Contributor

I've got a PR at #37 that does this work and a bunch of other changes.

@mullermp mullermp closed this in #37 Oct 27, 2024
@mullermp
Copy link
Contributor

Rack 3 will be the minimum dependency of aws-sessionstore-dynamodb ~> 3 and I will release the gem this week. I am uncertain if I will force that version in the aws-sdk-rails dependency which is currently pinned to ~> 2. I have a PR which does some refactoring in aws-sdk-rails and will eventually check for this gem to be loaded and not be a dependency (aws/aws-sdk-rails#147)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr/do-not-merge This PR should not be merged at this time.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants