I'm writing a modest transaction processor with an HTTP interface. The client posts the transaction details in the body of the POST.
All I really need is the OnBeginRequest handler. By the time I get to the bottom of this event, I'm done. No need to continue with the IIS pipeline processing on the server.
So I put a Response.End there at the bottom. This 'works' however it does throw an exception which I simply catch and suppress.
Should I be concerned about this from either a performance or quality standpoint?
Is there any way to accomplish this more cleanly?
private void OnBeginRequest(object sender, EventArgs e)
{
HttpContext ctx = HttpContext.Current;
try
{
if (ctx.Request.RequestType == "POST" && ctx.Request.IsSecureConnection)
{
// Here's where processing is implemented...
ctx.Response.StatusCode = 200;
ctx.Response.Write("OK");
}
else
{
ctx.Response.StatusCode = 403;
ctx.Response.Write("BAD");
}
}
catch (Exception ex)
{
ctx.Response.StatusCode = 500;
ctx.Response.Write("ERROR");
}
try
{
ctx.Response.End();
}
catch { }
}
in my opinion, this is the only way to terminate request using Response.End. another thing you could try is HttpContext.Current.ApplicationInstance.CompleteRequest(); This will end all further processing of the request. Your handler is not the only handler in the pipeline, so this will cancel further processing of other handlers after yours and send the response immediately to the client.
HttpApplication.CompleteRequest Method
Related
I have a custom process that needs to happen at the time of an invoice being released. Being this process calls out to a web service I need to wrap that code in a PXLongOperation per an Acumatica best practice. if I wrap the PXLongOperation in a try/finally block things work fine relative to the UI but if I run an integration test that executed the action item calling the PXLongOperation I now get the "The previous operation has not been completed yet." error. where these passed fine before adding the long operation.
Thanks for your help
[PXOverride]
public IEnumerable Release(PXAdapter adapter, ReleaseDelegate baseMethod)
{
//IEnumerable returnValue = null;
try
{
ARInvoice invoice = Base.Document.Current;
CtpARInvoiceExt invoiceExt = PXCache<ARInvoice>.GetExtension<CtpARInvoiceExt>(invoice);
if (invoice.DocType == "CRM")
{
PXLongOperation.StartOperation(Base, () => { ProcessClickToPayCreditMemoInvoice(invoice, invoiceExt); });
}
return baseMethod(new PXAdapter(Base.CurrentDocument));
}
//todo: I did find that this is raising an error behind the scenes but if this is commented out
// everything works as expected.
// I have found that even if this gets commented out the the integration tests that are using
// The Contract Bases Soap API are failing indicating that the process has not completed.
//catch (Exception e)
//{
// //todo: this is throwing an exception with message: The previous operation has not been completed yet.
// throw new PXException(e,CtpMessages.ClickToPayReleaseOverrideFailed, e.Message);
//}
finally
{
//... exit logic
}
}
The call that fails with the Contract Soap API is
InvokeResult invokeResult = SoapClient.Invoke(invoice, new ReleaseInvoice());
This design pattern can be used to force your method to wait until the long operation is completed.
TimeSpan timespan;
Exception ex;
while (PXLongOperation.GetStatus(docgraph.UID, out timespan, out ex) == PXLongRunStatus.InProcess)
{ }
// should be finished now
// return baseMethod...
I'm developing an android app that receives and processes mail messages. The app must be connected to an IMAP server and keep the connection alive, so it can see and process new mail messages instantly (mails contains json data from a mail api server). The app have two modes, manual and live connection. Here is some of my code:
class Idler {
Thread th;
volatile Boolean isIdling=false;
boolean shouldsync=false;//we need to see if we have unseen mails
Object idleLock;
Handler handler=new Handler();
IMAPFolder inbox;
public boolean keppAliveConnection;//keep alive connection, or manual mode
//This thread should keep the idle connection alive, or in case it's set to manual mode (keppAliveConnection=false) get new mail.
Thread refreshThread;
synchronized void refresh()
{
if(isIdling)//if already idling, just keep connection alive
{
refreshThread =new Thread(new Runnable() {
#Override
public void run() {
try {
inbox.doCommand(new IMAPFolder.ProtocolCommand() {
#Override
public Object doCommand(IMAPProtocol protocol) throws ProtocolException {
//Why not noop?
//any call to IMAPFolder.doCommand() will trigger waitIfIdle, this
//issues a "DONE" command and waits for idle to return(ideally with a DONE server response).
// So... I think NOOP is unnecessary
//protocol.simpleCommand("NOOP",null); I'm not issuing noop due to what I said ^
//PD: if connection was broken, then server response will never arrive, and idle will keep running forever
//without triggering messagesAdded event any more :'( I see any other explanation to this phenomenon
return null;
}
});
} catch (MessagingException e) {
e.printStackTrace();
}
}
},"SyncThread");
refreshThread.start();
}
else
{
getNewMail();//If manual mode keppAliveConnection=false) get the new mail
}
}
public Idler()
{
th=new Thread(new Runnable() {
#SuppressWarnings("InfiniteLoopStatement")
#Override
public void run() {
while (true)
{
try {
if(refreshThread !=null && refreshThread.isAlive())
refreshThread.interrupt();//if the refresher thread is active: interrupt. I thing this is not necessary at this point, but not shure
initIMAP();//initializes imap store
try {
shouldsync=connectIMAP()||shouldsync;//if was disconnected or ordered to sync: needs to sync
}
catch (Exception e)
{
Thread.sleep(5000);//if can't connect: wait some time and throw
throw e;
}
shouldsync=initInbox()||shouldsync;//if inbox was null or closed: needs to sync
if(shouldsync)//if needs to sync
{
getNewMail();//gets new unseen mail
shouldsync=false;//already refreshed, clear sync "flag"
}
while (keppAliveConnection) {//if sould keep idling "forever"
synchronized (idleLock){}//MessageCountListener may be doing some work... wait for it
isIdling = true; //set isIdling "flag"
handler.removeCallbacksAndMessages(null);//clears refresh scheduled tasks
handler.postDelayed(new Runnable() {
#Override
public void run() {
refresh();
}
},1200000);//Schedule a refresh in 20 minutes
inbox.idle();//start idling
if(refreshThread !=null && refreshThread.isAlive())
refreshThread.interrupt();//if the refresher thread is active: interrupt. I thing this is not necessary at this point, but not shure
handler.removeCallbacksAndMessages(null);//clears refresh scheduled tasks
isIdling=false;//clear isIdling "flag"
if(shouldsync)
break;//if ordered to sync... break. The loop will handle it upstairs.
synchronized (idleLock){}//MessageCountListener may be doing some work... wait for it
}
}
catch (Exception e) {
//if the refresher thread is active: interrupt
//Why interrupt? refresher thread may be waiting for idle to return after "DONE" command, but if folder was closed and throws
//a FolderClosedException, then it could wait forever...., so... interrupt.
if (refreshThread != null && refreshThread.isAlive())
refreshThread.interrupt();
handler.removeCallbacksAndMessages(null);//clears refresh scheduled tasks
}
}
}
},"IdlerThread");
th.start();
}
private synchronized void getNewMail()
{
shouldsync=false;
long uid=getLastSeen();//get last unprocessed mail
SearchTerm searchTerm=new UidTerm(uid,Long.MAX_VALUE);//search from las processed message to the las one.
IMAPSearchOperation so=new IMAPSearchOperation(searchTerm);
try {
so.run();//search new messages
final long[] is=so.uids();//get unprocessed messages count
if (is.length > 0) {//if some...
try {
//there are new messages
IMAPFetchMessagesOperation fop=new IMAPFetchMessagesOperation(is);
fop.run();//fetch new messages
if(fop.messages.length>0)
{
//process fetched messages (internally sets the last seen uid value & delete some...)
processMessages(fop.messages);
}
inbox.expunge();//expunge deleted messages if any
}
catch (Exception e)
{
//Do something
}
}
else
{
//Do something
}
}
catch (Exception e)
{
//Do something
}
}
private synchronized void initIMAP()
{
if(store==null)
{
store=new IMAPStore(mailSession,new URLName("imap",p.IMAPServer,p.IMAPPort,null,p.IMAPUser,p.IMAPPassword));
}
}
private boolean connectIMAP() throws MessagingException {
try {
store.connect(p.IMAPServer, p.IMAPPort, p.IMAPUser, p.IMAPPassword);
return true;
}
catch (IllegalStateException e)
{
return false;
}
}
//returns true if the folder was closed or null
private synchronized boolean initInbox() throws MessagingException {
boolean retVal=false;
if(inbox==null)
{//if null, create. This is called after initializing store
inbox = (IMAPFolder) store.getFolder("INBOX");
inbox.addMessageCountListener(countListener);
retVal=true;//was created
}
if(!inbox.isOpen())
{
inbox.open(Folder.READ_WRITE);
retVal=true;//was oppened
}
return retVal;
}
private MessageCountListener countListener= new MessageCountAdapter() {
#Override
public void messagesAdded(MessageCountEvent ev) {
synchronized (idleLock)
{
try {
processMessages(ev.getMessages());//process the new messages, (internally sets the last seen uid value & delete some...)
inbox.expunge();//expunge deleted messajes if any
} catch (MessagingException e) {
//Do something
}
}
}
};
}
The problem is: Sometimes when the user is refreshing or the app auto-refreshes, in the Alive Connection mode, one or both of this conditions keeps my app from getting new messages. This is from the javamail source code.
1: The IdlerThread enters monitor state in:
//I don't know why sometimes it enters monitor state here.
private synchronized void throwClosedException(ConnectionException cex)
throws FolderClosedException, StoreClosedException {
// If it's the folder's protocol object, throw a FolderClosedException;
// otherwise, throw a StoreClosedException.
// If a command has failed because the connection is closed,
// the folder will have already been forced closed by the
// time we get here and our protocol object will have been
// released, so if we no longer have a protocol object we base
// this decision on whether we *think* the folder is open.
if ((protocol != null && cex.getProtocol() == protocol) ||
(protocol == null && !reallyClosed))
throw new FolderClosedException(this, cex.getMessage());
else
throw new StoreClosedException(store, cex.getMessage());
}
2: The "refresherThread" enters wait state in:
void waitIfIdle() throws ProtocolException {
assert Thread.holdsLock(messageCacheLock);
while (idleState != RUNNING) {
if (idleState == IDLE) {
protocol.idleAbort();
idleState = ABORTING;
}
try {
// give up lock and wait to be not idle
messageCacheLock.wait();//<-----This is the line is driving me crazy.
} catch (InterruptedException ex) { }
}
}
As one of both of this threads "stops" running (wait & monitor state) my app is useless when reach this condition. In my country the mobile data network is very unstable, slow & expensive(GSM) So it must be failure resilient and take care about every transferred bit.
I guess the problem arises when the connection silently fails and the refresherThread starts to do its job. It issues a DONE command if idle is active, but, as the connection is gone, when idle tries to throw a FolderClosedException, one or both threads gets locked indefinitely.
So, my question is: Why is this situation arising and how to prevent it? How can I keep the idle loop securely running without getting locked?
I've tried a lot of things till exhaustion with no results.
Here are some threads I've read without getting a solution to my problem. In my country internet is EXTREMELY expensive too, so I can't research as much as I want, nor list all the urls I've visited looking for information.
JavaMail: Keeping IMAPFolder.idle() alive
JavaMail: Keeping IMAPFolder.idle() alive
Javamail : Proper way to issue idle() for IMAPFolder
Please, excuse my english. Any suggestion will be greatly appreciated. I've heard about this site strictness, so please be gentle, I'm new over here.
Be sure to set the timeout properties to make sure you don't hang waiting for a dead connection or server.
Instead of issuing a nop command directly, you should call Folder.isOpen or Folder.getMessageCount; they'll issue the nop command if needed.
If the folder is closed asynchronously (FolderClosedException), you'll need to restart the idle loop.
I have created a POST endpoint using DropWizard.
#POST
#Timed
public String runPageSpeed(#RequestParam String request) {
try {
JSONObject requestJSON = new JSONObject(request);
JSONArray urls = requestJSON.getJSONArray("urls");
process(urls); // this takes around 10 minutes to complete
return "done";
} catch (Exception e) {
throw new WebApplicationException("failed", Response.Status.INTERNAL_SERVER_ERROR);
}
}
process(urls); takes around 10 minutes to complete, so if we call this endpoint, it takes more than 10 minutes to get the response.
I want process(urls); to run in the background after receiving the URLs from the request and immediately return a response to the user.
I tried the following code using threads:
#POST
#Timed
public String runPageSpeed(#RequestParam String request) {
try {
JSONObject requestJSON = new JSONObject(request);
JSONArray urls = requestJSON.getJSONArray("urls");
Thread thread = new Thread() {
public void run() {
process(urls); // this takes around 10 minutes to complete
}
};
thread.start();
return "done";
} catch (Exception e) {
throw new WebApplicationException("failed", Response.Status.INTERNAL_SERVER_ERROR);
}
}
This works, but are there any issues if I use this approach, especially at a high volume?
DropWizard users should promote using CompletableFuture for async handling as it is the safest for handling background processing. With CompletableFuture you can move the heavyweight task to a background thread and simultaneously continue with the lightweight task thus can also send back a response to the client.
#POST
#Timed
public String runPageSpeed(#RequestParam String request) {
try {
JSONObject requestJSON = new JSONObject(request);
JSONArray urls = requestJSON.getJSONArray("urls");
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
// perform heavyweight task
process(urls); // this takes around 10 minutes to complete
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// perform lightweight task
return "done";
} catch (Exception e) {
throw new WebApplicationException("failed",
Response.Status.INTERNAL_SERVER_ERROR);
}
}
CompletableFuture helps in every aspects whether its using the return value of first complex task into second function or notifying on failure with the vast variety of methods it provides
runAsync()
supplyAsync()
thenApply()
thenAccept()
thenRun()
exceptionally()
handle()
You can also chain the CompletableFuture using thenCompose() and thenCombine() which is used when one task is dependent upon others.
I have got a REST-API in my Java Web Application. This has a method to take orders from a customer's Android app (client) and send (after a bunch of tasks, like price calculating etc.) a response back to the client.
#POST
#Path("order")
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public OrderResponse takeOrder(OrderRequest request
) throws IOException {
OrderResponse response = new OrderResponse();
String token = request.getTokenString();
CustomerSession session = sessionPool.getSession(token);
if (session != null) {
OrderHeader order = new OrderHeader();
order.setFkOrderHeaderCustomerID(session.getFkCustomerID());
order.setOrderCreationDate(new Date());
Tasks as getting the session for authentication etc. have to be done synchronously, sure. 'Cause the response for the clients depends on it's success or failure.. So far so good.
At the end of this method the client gets an email about the state of his order request.
Email email = EmailGenerator.createOrderEmail(order);
try {
emailService.send(email);
} catch (MessagingException ex) {
Logger.getLogger(CustomerREST.class.getName()).log(Level.SEVERE, null, ex);
}
response.setStatus(OrderStatusEnum.SUCCESS);
} else {
response.setStatus(OrderStatusEnum.TOKEN_INVALID);
}
return response;
}
This sometimes takes up to a few seconds for which the client has to wait for the response. That hurts.
Is there any way to send the response and do that email stuff in the background?
Thread mailingThread = new Thread() {
#Override
public void run() {
try {
Email email = EmailGenerator.createOrderEmail(order);
emailService.send(email);
} catch (MessagingException | IOException ex) {
Logger.getLogger(CustomerREST.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
mailingThread.start();
Thaks Kyle! This seems to do what I attempted!
I'm using Cucumber to test my service when it is deployed to a container. The request contains a URL the service calls when the operation is successful. What is a good way to create a Cucumber test that waits for the Http callback? The Gherkin script would look something like.
Scenario: Process Order
Given An Order has been submitted
When the Order is processed
Then the order process service calls back with a successful status message
What would the Java glue code look like?
Here's the solution I came up with using an embedded http server. In the OrderSteps.java glue code I added a class used to start the server on another thread.
private static class Callback implements Runnable
{
public void run()
{
HttpServer server;
try
{
server = HttpServer.create(new InetSocketAddress(8000), 0);
server.createContext("/callback", new CallbackHandler());
server.setExecutor(null); // creates a default executor
server.start();
}
catch (IOException e)
{
logger.debug("HTTP server loop failure.", e);
}
}
static class CallbackHandler implements HttpHandler
{
#Override
public void handle(HttpExchange t) throws IOException
{
// Read the message and set the global variable
// which informs the main test thread a callback
// has been received.
InputStream is=t.getRequestBody();
byte[] buf=new byte[1000];
int len=is.read(buf);
OrderSteps.receivedCallback=new String(buf,0,len);
String response = "Callback received.";
t.sendResponseHeaders(200, response.length());
// Send response
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
}
Then in the OrderSteps class, in the step/method that publishes the Order, the server thread is started and then the order is submitted. This guarantees the server will receive the callback, since it is listening before the order is submitted.
// Start a listener for the callback.
Thread callbackThread = new Thread(new Callback());
callbackThread.start();
In the step/method that checks if the callback was received, there's a loop checking the static variable to see if it has been set.
// Allow 5 seconds for the callback to occur.
for (int i = 0; i < 5; i++)
{
if (receivedCallback != null) {
break;
}
Thread.sleep(1000);
}
if (receivedCallback == null) fail("Callback was not received.");
assertEquals("Expected callback message", receivedCallback);