I have made a simple chat application in PHP/Ajax/MySQL.
I am regularly calling these two methods-
setInterval("GetChatParticipants()",5000);
setInterval("GetChatMessages()",1000);
Now as per client design, there's no Logout or Sign Out button, so I want to detect when user closes the browser and at that time I have to delete the participant record from the database. I dont want to use onbeforeunload as Chrome refuses to accept Ajax requests on window unload event.
So I am thinking of implementing in Ajax by making repeated reqests. But the question is how exactly shall I do that. Shall I update the Participant table with last_active_time and if the difference between current time and that last_active_time is , say, more than 10 min, then I should delete the user? Is it a practical solution or could there be a better one?
You have the best solution IMO. In Javascript create a "ping" function that pings every minute / two minutes etc with a session ID unique to that browser/session. Have a sessions table on your server and update when you get a ping. Have another script that looks for entries that have not been pinged for long periods and close the sessions.
I've had this structure running for thousands of concurrent users on one site, and I had to drop the ping down from 1 minute to every 2 minutes when load got heavyish (that was on 2 load balanced servers while running the rest of the site too). Obviously you make your ping approx 45% of the time-out time (so if one fails, a second should hit). It's a simple process that can handle the load.
Edit: don't use "setInterval" for the ping, but user "setTimeout" when each ping either returns or fails. Otherwise, with setInterval, if your server gets too loaded then the pings queue, never respond and queue some more. You get a meltdown of the server as all server sockets are used, then you can't connect by ssh to fix it... not a moment I was proud of.
Yes it is practical solution and then only one you can rely on, so, no matter what else you use in addition to that, this one final check should be in your logic at all times. Said that, combining several methods will give you more possibilities to detect user leaving early. Add onbeforeunload for browsers that support it. Add "log out" button for clients coming from insecure location that want to log out right now when leaving PC and finally, check for inactivity.
Yes, it is practical solultion. The only difference is where to store information about user ping. You can do it in database or in key-value storage like memcached. I prefer the second one as I think it takes lesser resources.
Related
I'm creating a PHP script that will allow a user to log into a website and execute database queries and do other actions that could take some time to complete. If the PHP script runs these actions and they take too long, the browser page times out on the user end and the action never completes on the server end. If I redirect the user to another page and then attempt to run the action in the PHP script, will the server run it even though the user is not on the page? Could the action still time out?
In the event of long-running server-side actions in a web application like this, a good approach is to separate the queueing of the actions (which should be handled by the web application) from the running of the actions (which should be handled by a different server-side application).
In this case it could be as simple as the web application inserting a record into a database table which indicates that User X has requested Action Y to be processed at Time Z. A back-end process (always-running daemon, scheduled script, whatever you prefer) would be constantly polling that database table to look for new entries. ("New" might be denoted by something like an "IsComplete" column in that table.) It could poll every minute, every few minutes, every hour... whatever is a comfortable balance between server performance and the responsiveness of an action beginning when it's requested.
Once the action is complete, the server-side application that ran the action would mark it as complete in the database and would store the results wherever you need them to be stored. (Another database table or set of tables? A file? etc.) The web application can check for these results whenever you need it to (such as on each page load, maybe there could be some sort of "current status" of queued actions on each page so the user can see when it's ready).
The reason for all of this is simply to keep the user-facing web application responsive. Even if you do things like increase timeouts, users' browsers may still give up. Or the users themselves may give up after staring at a blank page and a spinning cursor for too long. The user interface should always respond back to the user quickly.
You could look at using something like ignore_user_abort but that is still not ideal in my opinion. I would look at deferring these actions and running them through a message queue. PHP comes with Gearman - that is one option. Using a message queue scales well and does a better job ensuring the request actions actually get completed.
Lots on SO on the subject... Asynchronous processing or message queues in PHP (CakePHP) ...but don't use Cake :)
set_time_limit() is your friend.
If it were me, I would put a loading icon animation in the user interface telling them to wait. Then I would execute the "long process" using an asynchronous AJAX call that would then return an answer, positive or negative, that you would pass to the user through JavaScript.
Just like when you upload pictures to Facebook, you can tell the user what is going on. Very clean!
I'm writting a browser-based game. The client is in jQuery and the server is in PHP/MySQL.
It's a turn-based game, so most of the client-server communication is realised by call-respond (jQuery-PHP). That calls happens any time the user clicked button or any other active element. After call in JQuery, PHP controller creates some classes, connects to the database and returns respond. That communication is quite good for me, do not cause the problems with the number of connections etc. (it's similar to the standard trafic during using the website).
Unfortunatelly, I also need some 'calls' from server-side. The example is the list of active games to join. Client must be notify any time the game list has changed. And the maximum delay for that is no more than 1 second.
For now I make it by sending 'ping' call from client (jQuery) and server anserws with "nothing" most the time, or "game2 created" etc. But that 'pings' will be send every second from each of the players. And for each of them, the server will create classes and connect to the mysql which results with "Database connection error".
Is there any way to minimalise mysql connections and/or ajax calls?
I use standard www server, don't have root account.
Start with this:
But that 'pings' will be send every second from each of the players
Instead of calling every second the server by both players (which is actually 2 calls, with
the number going up for every player connected), you can optimize it by checking the idle time or how much time passed of doing nothing; if nothing has been returned for 2 continuous calls, you should increase the call delay to 2 seconds and then to 4 seconds etc. (just play with setInterval and make it run continuously);
This will allows some breathing to your app (i had my own game using this)
Next thing to do is the calling policy; Instead of calling the server in player's command, you can just store the player's command in a js array and every X seconds send
that array off; if no commands, no ajax call. Yes, you'll get a delay but think of many users
connected to a possible poor server...
You can also use comet technology if you want to push things further..
Having said that this may be a possible duplicate as mentioned by eggyal ..
about ping and response (client pings server scenario)
1) Have you considered writing temporary files (ie. Smarty compiled file with caching time X) ?
Once player Y has done its turn remove the file (or write something in that file).
Each player does an AJAX request with a game_id (or anything uniques) which will check existence of that compiled file. This will save you many mysql calls. You will call mysql if the caching time of the file has expired.
2) Ugly -> try if mysql persistent connections will help ( I am not sure )
I have a PHP function that I want to make available publically on the web - but it uses a lot of server resources each time it is called.
What I'd like to happen is that a user who calls this function is forced to wait for some time, before the function is called (or, at the least, before they can call it a second time).
I'd greatly prefer this 'wait' to be enforced on the server-side, so that it can't be overridden by dubious clients.
I plan to insist that users log into an online account.
Is there an efficient way I can make the user wait, without using server resources?
Would 'sleep()' be an appropriate way to do this?
Are there any suggested problems with using sleep()?
Is there a better solution to this?
Excuse my ignorance, and thanks!
sleep would be fine if you were using PHP as a command line tool for example. For a website though, your sleep will hold the connection open. Your webserver will only have a finite number of concurrent connections, so this could be used to DOS your site.
A better - but more involved - way would be to use a job queue. Add the task to a queue which is processed by a scheduled script and update the web page using AJAX or a meta-refresh.
sleep() is a bad idea in almost all possible situations. In your case, it's bad because it keeps the connection to the client open, and most webservers have a limit of open connections.
sleep() will not help you at all. The user could just load the page twice at the same time, and the command would be executed twice right after each other.
Instead, you could save a timestamp in your database for when your function was last invoked. Then, before invoking it, you should check the database to see if a suitable amount of time has passed. If it has, invoke the function and update the timestamp in the database.
If you're planning on enforcing a user login, than the problem just got a whole lot simpler.
Have a record inn the database listing users and the last time they used your resource consuming service, and measure the time difference between then and now. If the time difference is too low, deny access and display an error message.
This is best handled at the server level. No reason to even invoke PHP for repeat requests.
Like many sites, I use Nginx and you can use it's rate-limiting to block repeat requests over a certain number. So like, three requests per IP, per hour.
I'm trying to write a simple web chat app with PHP and AJAX.
I need to be aware of all the open sessions so that I can display a list of online users that are available to talk to. I also need to be aware of log outs because I use "both the sending and the receiving party are offline" as a condition for considering a chat session terminated and deleting the messages.
I'm keeping track of logged in users in a database: adding an entry on log-in and removing it on log-out works fine, but it's not comprehensive, as there are two other ways a user can become logged out:
server side session expires after inactivity.
client side cookie gets destroyed on browser close. Seems like a bad idea to use some sort of onclose triggered AJAX (what if the browser crashes or something?).
Simplest solution seems to be keeping a timestamp of last activity. I see some problems with this though:
AFAIK server-side expiry is chance based, so it wouldn't be accurate (and if I get the expiry time 3 minutes wrong, that's 3 minutes where some guy could be talking to an offline user wondering why no one is answering)
I'd have to constantly be querying the database to check every logged in users' last activity time compared to the current time. I don't see when / where I'd do this efficiently. It seems stupid to do this every single time the list of online users is needed.
Any help appreciated. I'm coding this myself because I'm not aware of any web chat frameworks that can integrate with my existing user database, do correct me if I'm wrong.
I don't think you're going to be able to do much to mitigate the constant querying to determine if users have logged off by closing the browser, internet connection issues, etc., but you could perhaps have each client make an AJAX request to the server every 5 seconds to update the last activity time, and have your application on the server consider the user "logged off" if they have missed 3-4 consecutive requests (ie, their last activity time is > 20 seconds).
On the client side, you could then check the last activity time every time your client sends a message to another user, and respond that they'd logged off if that had happened. If they attemped to open a chat with another user, you could also do an immediate call to check their status. Then you could perhaps check the status of all users in the user list every 30 seconds. That way your client gets pretty quick feedback if the person (s)he is chatting with drops offline unexpectedly.
You could invert your pattern, replacing your Ajax pull behavior with a push notification system.
In this way you can notify your chat users in realtime of login and logout of new chat members. I never did something like this in practice, but I've read about this kind of technology and it seems very interesting for cases like yours.
It's just a little bit harder than the ajax pull way, but once the main structure is implemented you can add functionality easily and the performance would be a lot better.
Some links I found that can be useful:
http://www.pubnub.com/blog/build-real-time-web-apps-easy
http://www.ape-project.org/
This is a railscast episode which deal with a javascript chat, the implementation is in rails, but even if you don't understand rails you should be able to follow it to get the core concepts: http://railscasts.com/episodes/260-messaging-with-faye
I'm not sure if you need both probability and divisor but here's what I do to auto logout people:
ini_set('session.gc_maxlifetime',3600); // 1 hour
ini_set('session.gc_probability',1); // it does garbage cleaning EVERY time
ini_set('session.gc_divisor',1); // it does garbage cleaning EVERY time
session_start();
Most of the data you are currently using and the data you need is stored in the PHP session - it's just not obvious how to derive the user id from the information.
If you switch to using a database bound session handler then it all becomes very easy. I had a quick google - and there are lots of examples out there. but a lot of them (e.g. this one) don't check for expiry on reading back the session. OTOH the example I've linked to does show adding the user id to the sesion record - which you'll need later. So the session read handler function should be something like:
read:
SELECT session_data, username
FROM sessions
WHERE session_id=' . session_id() . '
AND last_updated>= ' . date('YmdHis', time()-ini_get('session.gc_maxlifetime'))
And to get all the currently logged on users:
SELECT username
FROM sessions
WHERE last_updated>= ' . date('YmdHis', time()-ini_get('session.gc_maxlifetime'))
...and let the (overridden) session garbage collector automatically clear out redundant data.
HTH
First separate your concerns.
As far as 'list of online users' is concerned,you can use database & it seems you already have figured that out. (even if some one doesn't logs out properly,displaying a few extra online users won't do much damage)
Now for the chat app,for checking if a user is still online you will have to use ajax.
There is simply no other way.Of course there always can be a hack,I don't know.
see the image when you answer here (stackoverflow).it constantly checks if time has passed(& have you typed anything new) & saves a copy.
It seems that you are most concerned about performance and you have the implementation details figured out(mostly). Just change the type of the table that handles sessions to 'memory', this will reduce the performance cost of quering the db for every request to almost nothing as you are fetching data directly from RAM. Just make sure you delete the session every time a user explicity logs out, or you mark the user as inactive.
But no matter what you do implementing something that requires constant communication between client and server can never be done perfectly over HTTP. But if you put reasonable timeouts etc. it will work 99% of the time.
I am late to this party, but let me give my two cents.
In this particular scenario, there is no need for a push system for bad notifications. There is also no need for cron. Let me explain :
Say A,B and C are in a chat room & B's browser crashes, so his session expires. Right now , the server thinks B is still there but she is not. How do you update A & C? When A & C ASK for the update. Check B's last keepalive timestamp and figure out that their session has expired.
If all A,B & C crash, then this never happens I hear you ask. Who cares? There is no one to see our mistake now! The only downside is keeping up their chatroom alive which costs some database space. This can be cleaned up when another chat session is created.
A final gist :
Keep timestamps for the last time an action was taken.
Use a user event to loop through timestamps and take out the deadwood.
In case of users, this would be logging them out. In case of chatrooms, this would be those that have expired.
I've a particularly long operation that is going to get run when a
user presses a button on an interface and I'm wondering what would be the best
way to indicate this back to the client.
The operation is populating a fact table for a number of years worth of data
which will take roughly 20 minutes so I'm not intending the interface to be
synchronous. Even though it is generating large quantities of data server side,
I'd still like everything to remain responsive since the data for the month the
user is currently viewing will be updated fairly quickly which isn't a problem.
I thought about setting a session variable after the operation has completed
and polling for that session variable. Is this a feasible way to do such a
thing? However, I'm particularly concerned
about the user navigating away/closing their browser and then all status
about the long running job is lost.
Would it be better to perhaps insert a record somewhere lodging the processing record when it has started and finished. Then create some other sort of interface so the user (or users) can monitor the jobs that are currently executing/finished/failed?
Has anyone any resources I could look at?
How'd you do it?
The server side portion of code should spawn or communicate with a process that lives outside the web server. Using web page code to run tasks that should be handled by a daemon is just sloppy work.
You can't expect them to hang around for 20 minutes. Even the most cooperative users in the world are bound to go off and do something else, forget, and close the window. Allowing such long connection times screws up any chance of a sensible HTTP timeout and leaves you open to trivial DOS too.
As Spencer suggests, use the first request to start a process which is independent of the http request, pass an id back in the AJAX response, store the id in the session or in a DB against that user, or whatever you want. The user can then do whatever they want and it won't interrupt the task. The id can be used to poll for status. If you save it to a DB, the user can log off, clear their cookies, and when they log back in you will still be able to retrieve the status of the task.
Session are not that realible, I would probably design some sort of tasks list. So I can keep records of tasks per user. With this design I will be able to show "done" tasks, to keep user aware.
Also I will move long operation out of the worker process. This is required because web-servers could be restrated.
And, yes, I will request status every dozens of seconds from server with ajax calls.
You can have JS timer that periodically pings your server to see if any jobs are done. If user goes away and comes back you restart the timer. When job is done you indicate that to the user so they can click on the link and open the report (I would not recommend forcefully load something though it can be done)
From my experience the best way to do this is saving on the server side which reports are running for each users, and their statuses. The client would then poll this status periodically.
Basically, instead of checkStatusOf(int session), have the client ask the server of getRunningJobsFor(int userId) returning all running jobs and statuses.