利用google app engine开发一个定时器应用

2,303 views

最近对Google App Engine感兴趣。GAE是免费的(当然也有升级收费的),默认可以建立10个免费的web应用(不过我的账号可以建立25个免费应用^__^),至于配置,如果只是做简单的应用足够应付了,例如做一个定时抓取数据的应用,又或者用goagent搭建梯子。虽然GAE这么好的产品无法在国内(appspot.com在国内是无法访问的),但利用免费的资源做一些简单的事情还是很有意义的,对于如定时抓取数据,针对海外用户数据分析等等就非常有用了。

今天就写一篇关于google app engine定时器的文章。做这个定时器的前提是,假设你已经搭建好了google app engine的开发环境,使用Java语言版本。

google app engine关于定时任务的开发文档说的比较清楚,定时方式设置也比较多样。但最高频率只能到1分钟。如果做一个秒级别的定时器就没法完成,例如每个10秒执行一次,那就不能用scheduled tasks。这是可以使用scheduled tasks与task queue结合。当然也有另外的方式,使用Background threads(后台线程),通过while(true)+sleep(10000)的方式实现定时,但目前不探讨这种方式。

如果说scheduled tasks是用来定时执行任务的可以很好理解。task queue就是任务列队,就不大好理解。字面的理解就是等待执行的任务,默认是1秒可以执行5个任务。但是以什么方式执行呢?

我一开始以为,如果设置60秒执行5次任务,把任务添加到Queue中去,是不是就可以每隔10秒执行一次任务呢?然而这种理解是错误的。即使这样设置,task queue还是会在一瞬间执行列队里的任务,而不是间隔执行。

web应用都是请求方式执行的,而每个task queue就是包含一个请求的路径。每个task queue都是通过执行请求的方式执行任务,每个task queue又可以指定延时时间执行。

这样通过定时任务scheduled tasks每隔1分钟执行一个任务,scheduled tasks也是通过请求执行定时任务的。定义10秒执行一次任务,就是在scheduled tasks里的代码里,添加5个task queue,而每个scheduled tasks之间设置10秒的延时,这样60秒后执行所有的task queue,然后有重新运行下一个scheduled tasks的循环。

好了,下面是实现的代码过程。

1.新建一个Timer的google app engine项目

为了简单起见,新建项目时,将Google SDKs的默认勾选的选项Use Google Web Toolkit去掉。
这样默认生成的项目里,有一个TimerServlet.java的类。我们将这个默认的路径作为定时器的入口。定时器执行任务就会里面的代码。采用的的GET的请求方式。

2.配置cron.xml

如何让定时器执行TimerServlet的任务?这需要添加一个cron.xml的配置文件。里面的可以执行的路径,也可以添加多个任务。目前只添加一个执行任务,没隔一分钟执行一次timer的请求。在WEB-INFO目录下添加cron.xml文件。

cron.xml的文件内容:



    
        /timer
        timer every 1 minutes
        every 1 minutes
    

 这样就可以实现每隔一分钟执行一次TimerServlet的内容了。

3.添加task queue

以上定时任务只是每分钟执行一次。现在让任务执行每隔一分钟的时间间隔里执行5个task queue任务,而每个task queue之间延时10秒,这样就可以实现每隔10秒的定时运行任务了。

修改TimerServlet.java的源码后

package com.timer.main;

import java.io.IOException;

import javax.servlet.http.*;

import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
import com.google.appengine.api.taskqueue.TaskOptions.Method;

@SuppressWarnings("serial")
public class TimerServlet extends HttpServlet {
	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		resp.setContentType("text/plain");
		resp.getWriter().println("Timer running");
		Queue queue = QueueFactory.getDefaultQueue();
		for(int i=0;i<5;i++){
		queue.add(TaskOptions.Builder.withUrl("/task").param("key","间隔:"+10*i).method(Method.GET).etaMillis(System.currentTimeMillis()+10000*i));
		}
		
	}
}

以上代码就是添加了5个task queue,每个任务之间延时10秒,每个任务的请求路径是/task,每次请求的参数通过key传值,请求的方式是GET。

或许你会疑问:
(1).不是需要添加配置文件queue.xml吗?
因为是采取了默认的方式,所以不需要添加queue.xml。

(2).task是什么路径?
task就是下面要写的的TaskServlet.java类。

4.添加TaskServlet.java类

TaskServlet.java类就是task请求的路径,里面的内容才是真正要执行的的具体任务。目前这里只是实现一个打印获取timer传递过来的参数的代码的功能。

TaskServlet.java源码

package com.timer.main;

import java.io.IOException;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TaskServlet extends HttpServlet{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		resp.setContentType("text/plain");
		resp.getWriter().println("Task running");
		String key = req.getParameter("key");
//		resp.getWriter().println(new Date()+":key=="+key);
		System.out.println(new Date()+":key=="+key);
	}

}

为TaskServlet添加url映射,在WEB-INFO/web.xml,添加以下内容:


		
		Task
		com.timer.main.TaskServlet
	
	
		Task
		/task
	
	
	
     
        
            task
            /task/*
        
        
            admin
        
    

如果定时器为了安全起见,可以设置禁止外部用户访问,添加了对task和timer的任务的资源限制请求。
定时器之类的程序一般只允许内部程序访问,所以需要设置管理员权限,目前为了测试,只对task进行设置权限。
只允许管理员访问,可以设置

 
        
            task
            /task/*
        
        
            admin
        
    

如果允许所有人访问,可以设置

 
        
            task
            /task/*
        
        
            *
        
    

好了,目前项目可以完成了。

点击项目,运行Run As ->Web Application

在浏览器输入localhost:8888/timer
每次刷新timer请求,task queue会执行5个时隔10秒的任务请求如图-1。将应用发布到Google App Engine就可以执行每隔10秒的任务了。

timer

最后提供一份源码下载(为了方便网络传输,目前已将项目里lib的jar文件全部去除,如果要正常使用,需要添加相关的Google App Engine jar包,新建一个项目就有相应的jar)

Timer.zip

One thought on “利用google app engine开发一个定时器应用

  1. Pingback: 利用google app engine開發一個定時器應用

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>