Laravel - Store and Resume data for ALL the sessions - session

I use the laravel session with the database. I would like to know how to resume the informations are stored for ALL the sessions, that it means between all the row in the session table.
I am developing a booking room system. I use the session in this way:
First step:
A user searches all the available room for a certain date. A list appears with all the available rooms.
Second step:
After the user selects the room, it is redirected to the pay form.
In the first step when the user selects the room, the room id is stored in the session.
The things I would like to do is this:
The session is used to store all the room are chosen by the users, in case two or more users are looking for a same room in the same period. So that the rooms are not available in the search of other users until the first user pays.
Laravel has a payload column where it stores all the key and value but it is only a sequence of letter and number.

Laravel has a payload column where it stores all the key and value but it is only a sequence of letter and number
When you call \Session::put('foo', 'bar') the value es added into an associative array that keeps all data. If you are using database driver, then laravel serialize the array to store it as a string. That is why you only can see a lot of text. So, working with session will be so complicated because you has to serialize/unserialize over again.
How to block the room? Well, there are many ways to do that, all depends from your architecture. For example, you can store selected rooms in other table for 5 minutes (enough time to pay). Lets say you can work with two tables:
selected_rooms
------------------
number | expire_at
and...
rooms
number | beds | busy
The user search for a cool room. The system must ignores all the rooms that have references to selected_rooms table that has not been expired.
When the user select a room, you store it at selected_rooms room table with a expire_at value of now + 5 minutes.
When the user pay the room, you can remove it from selected_rooms. If the user just logout or just leave the pc, it does not matter, because after 5 minutes the room is available again

Related

Redis advice- when to group data and when to split it up

Hoping to get some sage advice from those that have been in the trenches, and can help me better understand when to keep data clustered together in Redis, and when to split it up.
I am working on a multi-tenant platform that has GPS data coming in every 3-5 seconds for each asset I track. As data is processed, we store additional information associated with the asset (i.e. is it on time, is it late, etc).
Each asset belongs to one or more tenant. For example, when tracking a family car, that car may exist for the husband, and the wife. Each needs to know where it is relative to their needs. For example, the car may be being used by the teenager and is on time for the husband to use it at 3:00 pm, but late for the wife to use it at 2:30 pm.
As an additional requirement, a single tenant may want read access to other tenants. I.E. the Dad wants to see the family car, and any teenager's cars. So the heirarchy can start to look something like this:
Super-Tenant --
--Super Tenant (Family)
--Tenant (Dad)
--Vehicle 1
--Gps:123.456,15.123
--Status:OnTime
--Vehicle 2
--Gps:123.872,15.563
--Status:Unused
--Tenant (Mom)
--Vehicle 1
--Gps:123.456,15.123
--Status:Late
--Vehicle 2
--Gps:123.872,15.563
--Status:Unused
--Tenant (Teenager)
--Vehicle 1
--Gps:123.456,15.123
--Status:Unused
--Vehicle 2
--Gps:123.872,15.563
--Status:Unused
My question has to do with the best way to store this in Redis.
I can store by tenant - I.E. I can use a Key for Dad, then have a collection of all of the vehicles he has access to. Each time a new GPS location comes in (whether for Vehicle 1 or Vehicle 2), I would update the contents of the collection. My concern is that if there are dozens of vehicles that we would be updating his collection way to often.
Or
I can store by tenant, then by vehicle. This means that when Vehicle 1's GSP location comes in I will be updating information across 3 different tenants. Not to bad.
What gives me pause is that I am working on a website for Dad to see all his vehicles. That call is going to come in and ask for all Vehicles under the Tenant of Dad. If I split out the data so it is stored by tenant/vehicle, then I will have to store the fact that Dad has 2 vehicles, then ask Redis for everything in (key1,key2,etc).
If I make it so that everything is stored in a collection under the Dad tenant, then my request to Redis would be much simpler and will be asking for everything under the key Dad.
In reality, each tenant will have between 5-100 vehicles, and we have 100's of tenants.
Based on your experience, what would be your preferred approach (please feel free to offer any not offered here).
From your question it appears you're hoping to store everything you need under one key. Redis doesn't support nested hashes as-is. There are a few recommendations from this answer on how to work around.
Based on the update cadence of the GPS data, it's best to minimize the total number of writes required. This may increase the number of operations to construct a response on read; however, adding read only slave instances should allow you to scale reads. You can tune your writes with some pipelining of updates.
From what you have described it sounds like the updates are limited to the GPS and status of a vehicle for a user. The data requested on read would be for a single user view what their set of vehicle position and status is.
I would start with a Tenant stored as a hash with the user's name, and a field referenceing the vehicles and sessions associated to the user. This is not really necessary if you take similar naming conventions, but shown as an option if additional user data needs cached.
- Tenant user-1 (Hash)
-- name: Dad (String)
-- vehicles: user-1:vehicles (String) reference to key for set of vehicles assigned.
-- sessions: user-1:sessions (String) reference to key for set of user-vehicle sessions.
The lookup of a the vehicles could be done with key formatting if none of the other tenant data is needed. The members would be references to the keys of vehicles.
- UserVechicles user-1:vehicles (Set)
-- member: vehicle-1 (String)
This would allow lookup of the details for the vehicle. Vehicles would have their position. You could include a field to reference a vehicle centric schedule of sessions similar to the user sessions below. Also you could place a vehicle name or other data if this is also required for response.
- Vehicle: vehicle-1 (Hash)
-- gps: "123.456,15.123" (String)
Store the sessions specific to a user in a sorted set. The members would be references to the keys storing session information. The score would be set to a timestamp value allowing range lookups for recent and upcoming sessions for that user.
- Schedule user-1:sessions
-- member: user-1:vehicle-1:session-1 (String)
-- score: 1638216000 (Float)
Tenant Sessions on a vehicle you could go simply with the listing of the status in a string. An alternative here is shown that would allow storing additional state of scheduled and available times if you need to support vehicle centric views of a schedule. Combining this with a sorted-set of vehicle sessions would round this out.
- Session user-1:vehicle-1:session-1 (Hash)
-- status: OnTime (String)
-- scheduled_start: 1638216000 (String) [optional]
-- scheduled_end: 1638216600 (String) [optional]
-- earliest_available: 1638215000 (String) [optional]
If you're not tracking state elsewhere you could use a hash to store the counters for the cache objects you have for when it comes time to issue a new one. Read and increment these when adding new cache objects.
- Globals: global (Hash)
-- user: 0
-- vehicle: 0
-- session: 0
For updates you would have: 200k write operations per update cycle.
100k tenants-vehicles (1000 tenants * 100 vehicles/tenant) each with
1 HSET vehicle
1 HSET session
Pipelining and tuning the number of requests in the pipeline can improve write performance, but I would anticipate you should be able to complete all writes in <2s.
For a read you would have something like: ~300 operations per user per request.
1 HGETALL user
1 ZRANGESTORE tempUSessions user-sessions LIMIT 200 (find up-to 200 sessions in a timeframe for the user)
200 HGETALL session
1 SMEMBERS user-vehicles (find all vehicles for the user)
100 HGET vehicle gps (get vehicle location for all vehicles)
Considerations:
A process to periodically remove sessions and their references after they pass would keep the memory from growing unbounded and performance consistent.
Adding some scripts to allow for easier updates to the cache when a new user or vehicle is added and for returning the state you described needing for display to a user would round this out.

How to get number of session in laravel project?

I have a basic laravel project which have login, logout and some others basic public pages.
I would like to count all session for the current time(now time). Any session that should be count login user or visit any public pages.
From this project, I would like to know how many session is running?
What I understand from your question is, you want a feature in your application where you can count number of user that are logged in to the application.
If that's the case then as stated above you can hack a way around by adding a bool column in users table or whatever table you are using to store users, and whenever any user logs in, you change that column value to 1 and when the user logs out you change the column value to 0.
This way you can count the users by using that column where the column value is true or 1.
Hope this solves your problem.

How to store sessions of a telegram bot user in my db

I wanna code a telegram bot, so when I gonna receive messages from a user I should know about last message he/she sent to me and in which step does he/she located. So I should store sessions of the user (I understood this when I searched) but I don't know what exactly should I do?
I know I need a table in a db that stores UserId, ChatId but I don't know these:
How to make a root for steps and store them in db (I mean how do I understand where the user is located now)
What are other columns that I need to store as a session?
How many messages should I store in the database? And do I need one row for each message?
If you just have to store session in your database you don't need to store messages. Maybe you could want to store also messages but it's not necessarily related.
Let's assume you have a "preferences" menu in your bot where the user can write his input. You ask for the name, age, gender etc.
How do your know when the user writes the input of it's about the name or the gender etc?
You save sessions in your db. When the bot receives the message you check in what session the user is in to run the right function.
An easy solution could be a sql database.
The primary key column is the telegram user ID ( you additionally can add a chat id column if it's intended to work both in private and group chats) and a "session" column TEXT where you log user steps. The session column can be NULL by default. If the bot expects the gender (because the user issued /gender command) you can update the column "session" with the word "gender" so when the message arrives you know how to handle it checking the gender column of that user id and as soon as you runned the right function, you update to NULL again the column "session".
you can create a db with these columns.
UserID, ChatID, State, Name, Age, Gender ...
on each incoming update you will check if user exists on you db then check the user's State and respond appropriately and update the state at the end.

Can I store in Redis this type of data?

I'm writing laravel application, where I want to show current user all other users on the page.
I want to use Redis to store this kind of information, so, for example, when user 1 visits page /item/35, then Redis must save this info:
{'/item/35': {1: last_visit_time_in_seconds}}
Where last_visit_time_in_seconds is unixtimestamp.
If two additional users visit same page, then Redis would contain:
{'/item/35': {1: seconds}, {12: seconds}, {2425: seconds}}
Users with ids 1, 12 and 2425 are viewing this page right now. If there are no updates for {1: seconds} for a short period of time (like 30 seconds), then this item must be removed from this item cache. Frontend periodically updates state of cache, so this is safeguard against user closing browser window.
May be there is a better way in Redis to store/get this kind of info (map from item to the list of users with their last visit time).
You can have the item Id as the key and the value would be a an array, which you will push to it any updates (new visits).
You can use bitmaps for that. It is easy and very very fast.
Your url + timestamp would be the key, and you would set the bit to 1 for every userId visiting.
SETBIT '/item/35:timestamp' userId 1
Then you do a BITCOUNT on this key:
BITCOUNT '/item/35:timestamp'
You can union daily or monthly bit counts and get super-fast analytics on daily, monthly visitors on a page. Here is a nice article on this.

Show all users currently signed in?

I am assuming I cannot do this using sessions but rather the DATABASE. So the user would sign in, it would set their TIMESTAMP and I display that from the database. Then it becomes deleted when the user logs out or their session is terminated. How would the code look for this?
The better question is, is my logic correct? Would this work? Does this make sense?
By default application servers store session data in temporary files on the server.
By storing session data in a database table you are able to create an interface that will show information about the users that are logged in. Apart from that, using this (database) approach is a serious advantage if you need to scale your application by adding more than one server.
One of the most popular ways to implement such a functionality is to create a session table containing your users' session data. This may look like:
create table session (
id number primary key,
data varchar(240),
timestamp date
);
The data column stores all the session data in a serialized form this is deserialized each time a user requests the data.
Serialization and deserialization may have inbuilt support depending on the platform you are using. For example, if you are using PHP, the functions session_encode and session_decode may be found useful.
You can't find out when a user logs out in PHP and the Javascript workarounds are a bit far from a stable solution.
A couple of things you need to do: Create a column in your user table called last_activity and update their last_activity to the current time whenever a user loads a page.
For a list of who's online, query the db for users with last_activity values more recent than 10 or 20 or whatever minutes ago.
To update the last_activity column use:
UPDATE users SET last_activity=CURRENT_TIMESTAMP() WHERE id=2
For a list of users online
SELECT * FROM users where last_activity >= (CURRENT_TIMESTAMP()-(60*20))

Resources