Do sessions work with multiple web dynos on Heroku? - ruby-on-rails

If you are running a Rails 3 app with multiple web dynos on Heroku,
Every time you hit the app, do you typically connect with a different web dyno?
Can sessions work across different web dynos?
Does it work for different Rails session stores (ActionDispatch::Session::CookieStore,
ActiveRecord::SessionStore, and ActionDispatch::Session::CacheStore)

In short yes - sessions will work across multiple web dynos.
Sessions work across web dynos - because Rail's design of session support allows it to. If anything, the web dyno model is exactly how Rail's was intended to be scaled horizontally.
1. Every time you hit the app, do you typically connect with a different web dyno?
Based on heroku documentation:
The routing mesh is responsible for determining the location of your application’s web dynos within the dyno manifold and forwarding the HTTP request to one of these dynos. Dyno selection is performed using a random selection algorithm.
So dyno selection is random... but that dyno has to have your application installed. So if you have more than one dyno, then you may end up connecting to a different dyno (which is important as this facilitates load balancing and high availability)
2. Can sessions work across different web dynos?
Yes. Most web stacks support sessions by doing the following:
Assigning a session id - which is a unique id, and it is usually set as a session cookie so that the browser will always send the id with ANY HTTP request to the originating host
Providing storage which maps the session id to the actual session data
So by this process, sessions can be supported as every inbound HTTP request has the session ID, which is accessible by the web dyno when it handles your request.
3. Does it work for different Rails session stores (ActionDispatch::Session::CookieStore, ActiveRecord::SessionStore, and ActionDispatch::Session::CacheStore)
ActionDispatch::Session::CookieStore
Yes. The cookie store stores encrypted session data as a cookie. So your browser sends all the session data (encrypted) back to the host, which is then decrypted for use within your app.
ActiveRecord::SessionStore
Yes. The cookie store stores encrypted session data in a database table. An ID is then assigned as a cookie. So your browser sends the ID to the host, which is then used to load the session data from the database. Since all web dynos have a connection to the DB, this means it is also supported.
ActionDispatch::Session::CacheStore
Yes but you need a cache store service (eg MemCache addon). The cookie store stores encrypted session data in a cache store (memcache), which is a shared service across all web dynos. An ID is then assigned as a cookie. So your browser sends the ID to the host, which is then used to load session data from the cache store (memcache).

I do not believe Heroku makes any effort to send consecutive requests to the same web dyno. I might be wrong and they make some effort, but even if they do, it isn't likely to be anything like reliable enough to count on for session management.
However, ActionDispatch::Session::CookieStore will definitely work because the data is stored in an encrypted client-side cookie. ActiveRecord::SessionStore will work because the data is stored in the database, which is presumably shared by all web dynos. ActiveDispatch::Session::CacheStore should work if you use a MemCached server shared between all clients, or a similar shared cache.
The only thing that wouldn't work is some sort of file-based session storage on the local filesystem, and situations like multiple Heroku dynos is exactly why that type of session storage is not common in modern web applications.

Related

Can users clear the service worker cache?

I've built a Progressive Web App that uses caching, but it's unclear to me whether users can (accidentally or on purpose) clear the service worker cache, which may clear my tracking data.
When a user clears their browsing data / cookies, this clears all site storage which includes the SW cache, cookies, local storage, indexeddb, and any other local caching system.
Furthermore, Ctrl-F5 forces a cache refresh, and is intended to abandon all cached content including service worker cache and just retrieve all content from the servers again.
"Clear site data" in Chrome 76 will delete the caches and the worker, however the deleted worker remains "activated and running". So that's a case that needs dealing with.

Rails - is new instance of Rails application created for every http request in nginx/passenger

I have deployed a Rails app at Engineyard in production and staging environment. I am curious to know if every HTTP request for my app initializes new instance of my Rails App or not?
Rails is stateless, which means each request to a Rails application has its own environment and variables that are unique to that request. So, a qualified "yes", each request starts a new instance[1] of your app; you can't determine what happened in previous requests, or other requests happening at the same time. But, bear in mind the app will be served from a fixed set of workers.
With Rails on EY, you will be running something like thin or unicorn as the web server. This will have a defined number of workers, let's say 5. Each worker can handle only one request at a time, because that's how rails works. So if your requests take 200ms each, that means you can handle approximately 5 requests per second, for each worker. If one request takes a long time (a few seconds), that worker is not available to take any other requests. Workers are typically not created and removed on Engineyard; they are set up and run continuously until you re-deploy, though for something like Heroku, your app may not have any workers (dynos) and if there are no requests coming in it will have to spin up.
[1] I'm defining instance, as in, a new instance of the application class. Each model and class will be re-instantiated and the #request and #session built from scratch.
According to what I have understood. No, It will definitely not initialize new instance for every request. Then again two questions might arise.
How can multiple user simultaneously login and access my system without interference?
Even though one user takes up too much processing time, how is another user able to access other features.
Answer to the first question is that HTTP is stateless, everything is stored in session, which is in cookie, which is in client machine and not in server. So when you send a HTTP request for a logged in user, browser actually sends the HTTP request with the required credentials/user information from clients cookies to the server without the user knowing it. Multiple requests are just queued and served accordingly. Since our server are very very fast, I feel its just processing instantly.
For the second query, your might might be concurrency. The server you are using (nginx, passenger) has the capacity to serve multiple request at same time. Even if our server might be busy for a particular user(Lets say for video processing), it might serve another request through another thread so that multiple user can simultaneously access our system.

How to configure login when using multiple servers running a distributed service (HAProxy, Apache, Ruby on Rails)

I have 3 servers running a website. I now need to implement login system and I am having problems with it as user gets a different behavior (logged in or logged out) depending on the server it gets connected to.
I am using Memcache for session store in Rails -
config.action_controller.session_store = :mem_cache_store
ActiveSupport::Cache::MemCacheStore.new("server1","server2","server3")
I thought the second line will either keep caches in sync or something like that ...
Each server has its own db with 1 master, 2 slaves. I have tried going the route of doing sessions in sql store but that really hurts sql servers and replication load becomes really heavy.
Is there an easy way to say, use this Memcache for all session store on all 3 servers?
Will that solve my problem?
I will really appreciate it.
I haven't used memcached to store sessions before ( I feel like redis is a better solution ), but I think as long as you have the
ActiveSupport::Cache::MemCacheStore.new("server1","server2","server3")
line on each of your application servers, your sessions should stay synced up.
I've had a lot of success with just using regular cookie sessions using the same setup you've described.

Make an ASP.NET MVC application Web Farm Ready

What will be the most efficient way to make an ASP.NET MVC application web-farm ready.
Most importantly sharing the current user's information (Context) and (not so important) cached objects such as look-up items (States, Street Types, counties etc.).
I have heard of/read MemCache but haven't seen a simple applicable way (documentation) on how to implement and test it.
Request context
Any request that hits a web farm gets served by an available IIS server. Context gets created there and the whole request gets served by the same server. So context shouldn't be a problem. A request is a stateless execution pipeline so it doesn't need to share data with other servers in any way shape or form. It will be served from the beginning to the end by the same machine.
User information is read from a cookie and processed by the server that serves the request. It depends then if you cache complete user object somewhere.
Session
If you use TempData dictionary you should be aware that it's stored inside Session dictionary. In a server farm that means you should use other means than InProc sessions, because they're not shared between IIS servers across the farm. You should configure other session managers that either use a DB or others (State server etc.).
Cache
When it comes to cache it's a different story. To make it as efficient as possible cache should as well be served. By default it's not. But looking at cache it barely means that when there's no cache it should be read and stored in cache. So if a particular server farm server doesn't have some cache object it would create it. In time all of them would cache some shared publicly used data.
Or... You could use libraries like memcached (as you mentioned it) and take advantage of shared cache. There are several examples on the net how to use it.
But these solutions all bring additional overhead of several things (like network and third process processing and data fetching etc.) if nothing else. So default cache is the fastest and if you explicitly need shared cache then decide for one. Don't share cache unless really necessary.

Shopping cart implementation

I want to integrate a shopping cart in my site. The cart should be such that it resets once the user signs out of the application. This can be either achieved via sessions or using the database tables.
What should be prefered out of the above two? Are there any security loop holes if this is handled via sessions?
In the security department, none of the two are prefered over the other. You should understand that both concepts are basically "sessions", but one is handled in the appdomain, the other is handled in the DB-domain.
Appdomain sessions:
Faster (No round-tripping to database)
Not scalable
Prone to concurrency problems on server farms
Sessions will be lost on server restart
Database sessions:
Slower (Roundtrips to the DB for each request)
Easier to scale on serverfarms
Sessions will be kept open on server restarts
You should consider how many users will be using your site. If you are looking at a lot, you are probably going to need multiple servers, in which case the database sessions will be your best bet, if you will stay with a single webserver / database server, then appdomain sessions will do fine.
I don't see why HttpSessions increase your security exposure - if your session is hijacked then presumably so is your DB access.
If you really intend that your user's cart should be transient then clearly your HttpSession is sufficient. Scaling app servers usually have session replication capabilities to deal with individual server failures.
I'm sceptical in the long term that such a volatile cart will always be what you want, I find it very convenient to browse around Amazon and assemble my cart, then just leave it for while. As it's probably not a great deal more work to persist your cart in a DB, I'd probably go for that.
I would use Sessions - no point of clogging up your DB on data that will be destroyed on log out.
Plus, Sessions are quite safe to use.

Resources