|
| 1 | +# Amazon DynamoDB Session Store |
| 2 | + |
| 3 | +The **Amazon DynamoDB Session Store** handles sessions for Ruby web applications |
| 4 | +using a DynamoDB backend. The session store is compatible with Rails and other |
| 5 | +Rack based frameworks. |
| 6 | + |
| 7 | +## Installation |
| 8 | + |
| 9 | +#### Rails Installation |
| 10 | + |
| 11 | +Install the session store gem by placing the following command into your |
| 12 | +Gemfile: |
| 13 | + |
| 14 | + gem 'aws-dynamodb-sessionstore' |
| 15 | + |
| 16 | +You will need to have an existing Amazon DynamoDB session table in order for the |
| 17 | +application to work. You can generate a migration file for the session table |
| 18 | +with the following command: |
| 19 | + |
| 20 | + rails generate dynamo_db_session_handler |
| 21 | + |
| 22 | +To create the table, run migrations as normal with: |
| 23 | + |
| 24 | + rake db:migrate |
| 25 | + |
| 26 | +Change the session store to `:dynamodb_store` by editing |
| 27 | +`config/initializers/session_store.rb` to contain the following: |
| 28 | + |
| 29 | + YourAppName::Application.config.session_store :dynamodb_store |
| 30 | + |
| 31 | +You can now start your Rails application with session support. |
| 32 | + |
| 33 | +#### Basic Rack Application Installation |
| 34 | + |
| 35 | +For non-Rails applications, you can create the Amazon DynamoDB table in a |
| 36 | +Ruby file using the following method: |
| 37 | + |
| 38 | + require 'aws-dynamodb-sessionstore' |
| 39 | + |
| 40 | + AWS::DynamoDB::SessionStore::Table.create_table |
| 41 | + |
| 42 | +Run the session store as a Rack middleware in the following way: |
| 43 | + |
| 44 | + require 'aws-dynamodb-sessionstore' |
| 45 | + require 'some_rack_app' |
| 46 | + |
| 47 | + options = { :secret_key => 'SECRET_KEY' } |
| 48 | + |
| 49 | + use AWS::DynamoDB::SessionStore::RackMiddleware.new(options) |
| 50 | + run SomeRackApp |
| 51 | + |
| 52 | +Note that `:secret_key` is a mandatory configuration option that must be set. |
| 53 | + |
| 54 | +## Detailed Usage |
| 55 | + |
| 56 | +The session store is a Rack Middleware, meaning that it will implement the Rack |
| 57 | +interface for dealing with HTTP request/responses. |
| 58 | + |
| 59 | +This session store uses a DynamoDB backend in order to provide scaling and |
| 60 | +centralized data benefits for session storage with more ease than other |
| 61 | +containers, like local servers or cookies. Once an application scales beyond |
| 62 | +a single web server, session data will need to be shared across the servers. |
| 63 | +DynamoDB takes care of this burden for you by scaling with your application. |
| 64 | +Cookie storage places all session data on the client side, |
| 65 | +discouraging sensitive data storage. It also forces strict data size |
| 66 | +limitations. DynamoDB takes care of these concerns by allowing for a safe and |
| 67 | +scalable storage container with a much larger data size limit for session data. |
| 68 | + |
| 69 | +### Configuration Options |
| 70 | + |
| 71 | +The following options are available to be set in |
| 72 | +`AWS::DynamoDB::SessionStore::Configuration`, which is used by the |
| 73 | +`RackMiddleware` class. These options can be set in the YAML configuration |
| 74 | +file in a Rails application, directly by Ruby code, or environment variables. |
| 75 | + |
| 76 | +<table> |
| 77 | +<tbody> |
| 78 | +<tr class="odd"> |
| 79 | +<th align="left"><p>Option Name</p></td> |
| 80 | +<th align="left"><p>Description</p></td> |
| 81 | +</tr> |
| 82 | +<tr class="even"> |
| 83 | +<td><p>:table_name</p></td> |
| 84 | +<td><p>The session table name.</p></td> |
| 85 | +</tr> |
| 86 | +<tr class="odd"> |
| 87 | +<td><p>:table_key</p></td> |
| 88 | +<td><p>The session table hash key name.</p></td> |
| 89 | +</tr> |
| 90 | +<tr class="odd"> |
| 91 | +<td><p>:secret_key</p></td> |
| 92 | +<td><p>The secret key for HMAC encryption.</p></td> |
| 93 | +</tr> |
| 94 | +<tr class="even"> |
| 95 | +<td><p>:consistent_read</p></td> |
| 96 | +<td><p>True/false depending on whether a strongly consistent read |
| 97 | + is desired.</p></td> |
| 98 | +</tr> |
| 99 | +<tr class="odd"> |
| 100 | +<td><p>:read_capacity</p></td> |
| 101 | +<td><p>The maximum number of reads consumed per second before |
| 102 | + DynamoDB returns a ThrottlingException.</p></td> |
| 103 | +</tr> |
| 104 | +<tr class="even"> |
| 105 | +<td><p>:write_capacity</p></td> |
| 106 | +<td><p>The maximum number of writes consumed per second before |
| 107 | + DynamoDB returns a ThrottlingException.</p></td> |
| 108 | +</tr> |
| 109 | +<tr class="odd"> |
| 110 | +<td><p>:raise_errors</p></td> |
| 111 | +<td><p>True/false depending on whether all errors should be raised |
| 112 | + up the Rack stack. See documentation for details.</p></td> |
| 113 | +</tr> |
| 114 | +<tr class="even"> |
| 115 | +<td><p>:dynamo_db_client</p></td> |
| 116 | +<td><p>The DynamoDB client used to perform DynamoDB calls.</p></td> |
| 117 | +</tr> |
| 118 | +<tr class="even"> |
| 119 | +<td><p>:max_age</p></td> |
| 120 | +<td><p>Maximum age in seconds from the current time of |
| 121 | + a session.</p></td> |
| 122 | +</tr> |
| 123 | +<tr class="odd"> |
| 124 | +<td><p>:max_stale</p></td> |
| 125 | +<td><p>Maximum time in seconds from the current time in which a |
| 126 | + session was last updated.</p></td> |
| 127 | +</tr> |
| 128 | +<tr class="even"> |
| 129 | +<td><p>:error_handler</p></td> |
| 130 | +<td><p>Error handling object for raised errors.</p></td> |
| 131 | +</tr> |
| 132 | +<tr class="even"> |
| 133 | +<td><p>:enable_locking</p></td> |
| 134 | +<td><p>True/false depending on whether a locking strategy should |
| 135 | + be implemented for session accesses.</p></td> |
| 136 | +</tr> |
| 137 | +<tr class="odd"> |
| 138 | +<td><p>:lock_expiry_time</p></td> |
| 139 | +<td><p>The time in milleseconds after which the lock |
| 140 | + will expire.</p></td> |
| 141 | +</tr> |
| 142 | +<tr class="even"> |
| 143 | +<td><p>:lock_retry_delay</p></td> |
| 144 | +<td><p>The time in milleseconds to wait before |
| 145 | + retrying to obtain a lock.</p></td> |
| 146 | +</tr> |
| 147 | +<tr class="odd"> |
| 148 | +<td><p>:lock_max_wait_time</p></td> |
| 149 | +<td><p>Maximum time in seconds a request will wait to obtain |
| 150 | + the lock before throwing an exception.</p></td> |
| 151 | +</tr> |
| 152 | +<tr class="even"> |
| 153 | +<td><p>:config_file</p></td> |
| 154 | +<td><p>File path to YAML configuration file</p></td> |
| 155 | +</tr> |
| 156 | +</tbody> |
| 157 | +</table> |
| 158 | + |
| 159 | +#### Environment Options |
| 160 | + |
| 161 | +Certain configuration options can be loaded from the environment. These |
| 162 | +options must be specified in the following format: |
| 163 | + |
| 164 | + DYNAMO_DB_SESSION_NAME-OF-CONFIGURATION-OPTION |
| 165 | + |
| 166 | +The example below would be a valid way to set the session table name: |
| 167 | + |
| 168 | + export DYNAMO_DB_SESSION_TABLE_NAME='sessions' |
| 169 | + |
| 170 | +### Rails Generator Details |
| 171 | + |
| 172 | +The generator command specified in the installation section will generate two |
| 173 | +files: a migration file, `db/migration/VERSION_migration_name.rb`, and a |
| 174 | +configuration YAML file, `config/dynamo_db_session.yml`. |
| 175 | + |
| 176 | +You can run the command with an argument that will define the name of the |
| 177 | +migration file. Once the YAML file is created, you can uncomment any of the |
| 178 | +lines to set configuration options to your liking. The session store will pull |
| 179 | +options from `config/dynamo_db_session.yml` by default if the file exists. |
| 180 | +If you do not wish to place the configuration YAML file in that location, |
| 181 | +you can also pass in a different file path to pull options from. |
| 182 | + |
| 183 | +### Garbage Collection |
| 184 | + |
| 185 | +You may want to delete old sessions from your session table. The |
| 186 | +following examples show how to clear old sessions from your table. |
| 187 | + |
| 188 | +#### Rails |
| 189 | + |
| 190 | +A Rake task for garbage collection is provided for Rails applications. |
| 191 | +By default sessions do not expire. See `config/dynamo_db_session.yml` to |
| 192 | +configure the max age or stale period of a session. Once you have configured |
| 193 | +those values you can clear the old sessions with: |
| 194 | + |
| 195 | + rake dynamo_db:collect_garbage |
| 196 | + |
| 197 | +#### Outside of Rails |
| 198 | + |
| 199 | +You can create your own Rake task for garbage collection similar to below: |
| 200 | + |
| 201 | + require "aws-dynamodb-sessionstore" |
| 202 | + |
| 203 | + desc 'Perform Garbage Collection' |
| 204 | + task :garbage_collect do |t| |
| 205 | + options = {:max_age => 3600*24, max_stale => 5*3600 } |
| 206 | + AWS::DynamoDB::SessionStore::GarbageCollection.collect_garbage(options) |
| 207 | + end |
| 208 | + |
| 209 | +The above example will clear sessions older than one day or that have been |
| 210 | +stale for longer than an hour. |
| 211 | + |
| 212 | +### Locking Strategy |
| 213 | + |
| 214 | +You may want the Session Store to implement the provided pessimistic locking |
| 215 | +strategy if you are concerned about concurrency issues with session accesses. |
| 216 | +By default, locking is not implemented for the session store. You must trigger |
| 217 | +the locking strategy through the configuration of the session store. Pessimistic |
| 218 | +locking, in this case, means that only one read can be made on a session at |
| 219 | +once. While the session is being read by the process with the lock, other |
| 220 | +processes may try to obtain a lock on the same session but will be blocked. |
| 221 | + |
| 222 | +Locking is expensive and will drive up costs depending on how it is used. |
| 223 | +Without locking, one read and one write are performed per request for session |
| 224 | +data manipulation. If a locking strategy is implemented, as many as the total |
| 225 | +maximum wait time divided by the lock retry delay writes to the database. |
| 226 | +Keep these considerations in mind if you plan to enable locking. |
| 227 | + |
| 228 | +#### Configuration for Locking |
| 229 | + |
| 230 | +The following configuration options will allow you to configure the pessimistic |
| 231 | +locking strategy according to your needs: |
| 232 | + |
| 233 | + options = { |
| 234 | + :enable_locking => true, |
| 235 | + :lock_expiry_time => 500, |
| 236 | + :lock_retry_delay => 500, |
| 237 | + :lock_max_wait_time => 1 |
| 238 | + } |
| 239 | + |
| 240 | +### Error Handling |
| 241 | + |
| 242 | +You can pass in your own error handler for raised exceptions or you can allow |
| 243 | +the default error handler to them for you. See the API documentation |
| 244 | +on the {AWS::DynamoDB::SessionStore::Errors::BaseHandler} class for more |
| 245 | +details. |
0 commit comments