diff --git a/doc/development/README.md b/doc/development/README.md index 83a1145c020..cfbbd5aaeaa 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -44,6 +44,7 @@ description: 'Learn how to contribute to GitLab.' - [`Gemfile` guidelines](gemfile.md) - [Pry debugging](pry_debugging.md) - [Sidekiq debugging](sidekiq_debugging.md) +- [Accessing session data](session.md) - [Gotchas](gotchas.md) to avoid - [Avoid modules with instance variables](module_with_instance_variables.md) if possible - [How to dump production data to staging](db_dump.md) diff --git a/doc/development/session.md b/doc/development/session.md new file mode 100644 index 00000000000..9edce3dbda0 --- /dev/null +++ b/doc/development/session.md @@ -0,0 +1,65 @@ +# Accessing session data + +Session data in GitLab is stored in Redis and can be accessed in a variety of ways. + +During a web request, for example: + +- Rails provides access to the session from within controllers through [`ActionDispatch::Session`](https://guides.rubyonrails.org/action_controller_overview.html#session). +- Outside of controllers, it is possible to access the session through `Gitlab::Session`. + +Outside of a web request it is still possible to access sessions stored in Redis. For example: + +- Session IDs and contents can be [looked up directly in Redis](#redis). +- Data about the UserAgent associated with the session can be accessed through `ActiveSession`. + +When storing values in a session it is best to: + +- Use simple primitives and avoid storing objects to avoid marshaling complications. +- Clean up after unneeded variables to keep memory usage in Redis down. + +## Gitlab::Session + +Sometimes you might want to persist data in the session instead of another store like the database. `Gitlab::Session` lets you access this without passing the session around extensively. For example, you could access it from within a policy without having to pass the session through to each place permissions are checked from. + +The session has a hash-like interface, just like when using it from a controller. There is also `NamespacedSessionStore` for storing key-value data in a hash. + +```ruby +# Lookup a value stored in the current session +Gitlab::Session.current[:my_feature] + +# Modify the current session stored in redis +Gitlab::Session.current[:my_feature] = value + +# Store key-value data namespaced under a key +Gitlab::NamespacedSessionStore.new(:my_feature)[some_key] = value + +# Set the session for a block of code, such as for tests +Gitlab::Session.with_session(my_feature: value) do + # Code that uses Session.current[:my_feature] +end +``` + +## Redis + +Session data can be accessed directly through Redis. This can let you check up on a browser session when debugging. + +```ruby +# Get a list of sessions +session_ids = Gitlab::Redis::SharedState.with do |redis| + redis.smembers("#{Gitlab::Redis::SharedState::USER_SESSIONS_LOOKUP_NAMESPACE}:#{user.id}") +end + +# Retrieve a specific session +session_data = Gitlab::Redis::SharedState.with { |redis| redis.get("#{Gitlab::Redis::SharedState::SESSION_NAMESPACE}:#{session_id}") } +Marshal.load(session_data) +``` + +## Getting device information with ActiveSession + +The [**Active Sessions** page on a user's profile](../user/profile/active_sessions.md) displays information about the device used to access each session. The methods used there to list sessions can also be useful for development. + +```ruby +# Get list of sessions for a given user +# Includes session_id and data from the UserAgent +ActiveSession.list(user) +```