Cancelling a Web Request
This is one of those where I'm not so much telling you something as I am asking for clarification of my own understanding.
Say you request a URL from the browser, such as "/database.nsf/Loop?OpenAgent". This agent loops from n=1 to n=1,000,000 and prints the value of n to the browser each time. If, half way through, you get bored and press the stop button on the browser, hit the escape key or even close the browser then what?
As I've always understood it the agent continues on regardless in the background. By the very nature of the stateless browser-server relationship on the web the server doesn't know if the person who started the conversation is still listening.
Imagine now that you've accidentally coded an infinite loop in the agent (we've all done it!). Once you realise you panic and close the browser. This doesn't help though. The only solution is to kill the HTTP task and/or restart the server. Or is it? I've always assumed so.
Assuming the server is still sending sending data back to the requesting machine, where does it all go - does the PC just receive it and then duly ignore it. What if you turn the PC off -- where does it go then?
In one of my finer moments I ran an infinate loop a couple of weeks back.(forgot to get next document in a while loop- well who hasn't)..The server (8.5) elegantly timed it out (did not complete in a etc etc) and spared my blushes!
Firstly your data doesn't "go" anywhere.
Domino does not have the ability to handle streaming of output (much to my chagrin). Domino batches up all of the output generated from an agent into a cache. When the agent has completed then it will send all of that data out to the browser. If during that time the browser has closed or the connection has been lost, then the data simply gets deleted.
However, as Nick says, if you do get yourself in an endless loop (guilty as charged), then the server will time-out the agent. Look at the server document and you will see settings for how long an agent is allowed to run for. Set it too long and you will seriously compromise your server. Set it too short and some of the more complicated agents won't finish in time. Personally, I think 5 mins is ideal.
Good point Dragon.
You say "the data simply gets deleted". By what? The receiving PC? Or does the server know the connection is lost? I thought there wasn't a connection as such and that a connection was re-created for each response sent.
Domino tries the connection back to the App, finds that it's no longer there and simply kills the output. Remember the connection was originated by the browser, so it is the browser that holds the connection open waiting. When the connection dies, there is nothing to go back, so Domino simply kills it's output buffer.
You can control the timeout on the server document. Go to "Internet Protocols...", "Domino Web Engine" and then at the bottom (left) you find the subtitle "Web Agents and Web Services" where you can control if they can run concurrently - and the timeout in seconds.
If I recall correctly, the timeout for web agents was introduced in version 5.
Aha. My thinking was flawed.
I was going to then ask why Domino can't then see the connection is gone and stop processing the agent, but having thought about it, this might not always be the required behaviour. For instance, you might want to trigger an agent from a browser - which performs a set of actions - and not care about the output/response, so you close the browser once it's running.
You can also issue the server console command to cancel the particular agent by issuing the command like ..
Tell Amgr Cancel 'your agent name'.
As Domino works now (might change in the future) the domino server has to render all the output to be able to set the Content-Length header to the length of the rendered object.
When this is done it then tries to send, first the header, and then the content. It is in the sending process that Domino can detect that the other party is not listening and discard the output.
You could write a DSAPI filter that would send a little bit of header data prior to rendering the design object and if the browser was not listening it could abort the request.
But I doubt you would gain much in real world scenarios. And you could still not stop the rendering half way trough.
I wouldn't let my users perform any action that took that long on the server to begin with. :P
I'd do it in batches of 1000 or so, coming from the browser, repeating whenever the browser got a success from the last 1000.
Wouldn't stop an infinite loop, though, of course.
This is a question I've often wondered about too. Thanks for asking it Jake! I'm intrigued by the answers.
@Venkat: With amgr you can only cancel agents started by amgr, i.e. scheduled agents. Web agents aren't started by amgr and therefore can't be stopped with the "tell amgr cancel" command.
Two questions that are kinda related:
1. Is there a way to get the server console to list all HTTP tasks that are currently running? ... what about open sessions?
2. Is there a way of killing a session remotely? ... for example, if I've logged into an app via a web browser, but forgot to log out, can I kill the open session using remote console?
What if you used a cookie on the users machine? Can you write to the cookie at significant points such as every 'n' number? If there is no response to writing to the cookie, then exit the agent.
@MattC: From the console you can "tell http show users", and if you're using Administrator there is an "Internet Users" section under Server... > Status. From there you can drop a user.
Not sure about doing that from the console... none of the servers here run http for me to test it out!
Been a while since I really did much admin, so if this is all wrong my apologies!!
@CJ: Thanks ...
However, I tested this both ways (Via server console and the Admin client) while I was authenticated via HTTP. When tested from the console, I received the message: "There are no current HTTP user sessions" ... when tested Via the Admin client, there were no listings at all.
Does this rely on any other server settings? (I'm also not much of an admin)
The server console reads that it opened a session for my ID. (Actually, it reads that it opened 2 sessions ... the second session was opened only a fraction of a second after the first ??)
Does that session denote my Notes session or my HTTP session? (I think I know the answer.)
@Matt: Sorry, I can't remember much more than I put. I'd give it a try, but like I said none of the servers here have domino running the HTTP task.
I seem to think that something may be related to the Session Authentication type under Internet Protocols > Domino Web Engine tab of the server config doc... but it's just as likely I'm remembering this for some other reason! Perhaps someone a bit more admin-y could shed some more light.
@CJ: I figured it had something to do with enabling session based authentication, but I'm not nearly "admin-y" enough to start fiddling.
It sure would be nice if there were a strait forward way of getting a list of all the HTTP users, with options to cut off each by name (or I.P.). Same with HTTP tasks.
This is why I don't consider myself a "Domino Developer" instead I consider myself a "Professional Help File Reader" ... that's P.H.F.R. ... so you'll know when you see it on CareerBuilder. ;-)
How about creating a profile document for each instance of the agent running, setting a profile field KeepExecuting to 1, and having the agent check for that field value after each batch of N entries processed. If you see the agent takes too long, you can edit the profile doc and set the field to 0.
When my http server is hang I usually use the command, this command will show you all your running threads:
"tell http show thread state"
for showing what is going on and why. Of course this can't help you to stop and started agent. I never was able to stop an started agent with an infinite loop without drastic actions.
this is the ouput:
Http Worker Thread ID [1c]: [Thread State is Idle]
Http Worker Thread ID [1d]: [Thread State is Idle]
Http Worker Thread ID [1e]: [Thread State is Idle]
Http Worker Thread ID [1f]: [Thread State is Idle]
Http Worker Thread ID [20]: Working session [4]: Session State [Processing Request] : GET *****************
Http Worker Thread ID [21]: [Thread State is Idle]
you may be able to get the amgr to run agents by having the agent you call grab the inbound info, drop it into a note and calling the agent via runOnServer(noteID) but i haven't tried it. having a 'kill' process agent would also be possible to make AJAX calls which output to the domino console command line but how would you know which agent to kill? sounds like a disaster waiting to happen :(