TurboManage

David Chandler's Journal of Java Web and Mobile Development

  • David M. Chandler


    Web app developer since 1994 and former Developer Advocate with Google now residing in Colorado. Besides tech, I enjoy landscape photography and share my work at ColoradoPhoto.gallery.

  • Subscribe

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 242 other followers

  • Sleepless Nights…

    November 2009
    S M T W T F S
    « Oct   Dec »
    1234567
    891011121314
    15161718192021
    22232425262728
    2930  
  • Blog Stats

    • 849,257 hits

Deferred.defer() is a thing of beauty

Posted by David Chandler on November 20, 2009

How do you do background processing in an AppEngine environment? The AppEngine experimental Task Queues API provides a way using Web hooks, but it’s a bit of a pain because you have to package each background task as a servlet.

Comes Vince Bonfanti of New Atlanta to the rescue with a Java implementation of Nick Johnson’s original Deferred.defer implementation in Python. Now queuing a task for background processing is as simple as creating a task and calling Deferred.defer(task). Here’s an example task to send an email to the application administrator:

package com.roa.server.service.task;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Properties;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.ServletException;

import com.newatlanta.appengine.taskqueue.Deferred;

	public class AdminEmailTask implements Deferred.Deferrable
	{
		private String msgBody;
		private String msgSubject;

		public AdminEmailTask(String msgSubject, String msgBody)
		{
			this.msgSubject = msgSubject;
			this.msgBody = msgBody;
		}

		@Override
		public void doTask() throws ServletException, IOException
		{
			Properties props = new Properties();
			Session session = Session.getDefaultInstance(props, null);

			try
			{
				Message msg = new MimeMessage(session);
				msg.setFrom(new InternetAddress("admin@example.com", "admin"));
				msg.addRecipient(Message.RecipientType.TO, new InternetAddress(
					"admin@example.com", "admin"));
				msg.setSubject(msgSubject);
				msg.setText(msgBody);
				Transport.send(msg);
			}
			catch (AddressException e)
			{
				throw new ServletException(e);
			}
			catch (MessagingException e)
			{
				throw new ServletException(e);
			}
			catch (UnsupportedEncodingException e)
			{
				throw new ServletException(e);
			}

		}
	}

And here’s an example of queuing the task inside a gwt-dispatch ActionHandler:

package com.roa.server.handler.admin;

import java.io.IOException;

import net.customware.gwt.dispatch.server.ActionHandler;
import net.customware.gwt.dispatch.server.ExecutionContext;
import net.customware.gwt.dispatch.shared.ActionException;

import com.google.inject.Inject;
import com.newatlanta.appengine.taskqueue.Deferred;
import com.roa.admin.shared.rpc.AdminEmailAction;
import com.roa.admin.shared.rpc.AdminEmailResult;
import com.roa.server.service.task.AdminEmailTask;
import com.turbomanage.gwt.server.PMF;

public class AdminEmailHandler implements ActionHandler<AdminEmailAction, AdminEmailResult>
{

	@Inject
	private PMF pmf;

	@Override
	public AdminEmailResult execute(AdminEmailAction action, ExecutionContext ctx)
		throws ActionException
	{
		AdminEmailTask adminEmailTask = new AdminEmailTask(action.getEmailSubject(), action
			.getEmailBody());
		try
		{
			Deferred.defer(adminEmailTask);
		}
		catch (IOException e)
		{
			throw new ActionException(e);
		}
		return new AdminEmailResult();
	}

	@Override
	public Class<AdminEmailAction> getActionType()
	{
		return AdminEmailAction.class;
	}

	@Override
	public void rollback(AdminEmailAction arg0, AdminEmailResult arg1, ExecutionContext arg2)
		throws ActionException
	{
		// TODO Auto-generated method stub

	}

}

You might ask why you’d use a deferred task like this to send an email? In this example, there really is no reason to, but imagine you were sending 1000 emails at once. In order to guarantee you won’t exceed AppEngine’s free quota of 8 recipients / minute, you could set up your deferred queue in queue.xml with that rate and then call Deferred.defer() for each recipient rather than calling the mail API directly 1000 times in a loop. That way, the AppEngine task queuing facility throttles your mail API calls.

Here’s a link to the whole discussion thread and Vince’s code.

If you’d like to see this added to the Task Queues API, please star this issue.

6 Responses to “Deferred.defer() is a thing of beauty”

  1. […]   « Deferred.defer() is a thing of beauty […]

  2. […] access to the ServletContext, either. The class happens to be a background task that implements the Deferrable interface, which for sake of interface simplicity does not provide access to the ServletContext […]

  3. […] using ServletUnit. The test case below creates a simple test case using Vince Bonfanti’s Deferred task servlet, verifies that it has been enqueued properly, and then invokes it using […]

  4. Where is a home of library?

  5. Andrei Nistor said

    Now the Deferred is part of GAE, how would you rewrite this code?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: