PR

AppsスプレッドシートとApp Engineのデータ交換を完成させる

2013年12月24日(火)
清野 克行

2. Datastoreに書き込まれたスプレッドデータをGoogle Driveから読み取り表示する

ここからは、今回連載2番目のテーマである、Drive上スプレッドデータをApp Engineから読み取ってDatastoreに書き込む処理の自動化について見ていきます。

2. 1 Pull Taskを使用した処理の概要

App Engineには、負荷の大きな処理を分割して並行実行する機能としてTask Queueサービスがあります。Task QueueにはPush QueueとPull Queueの2種類の処理方式がありますが、ここではPull Queueを使用します。Pull Queueでは、ユーザーが指定した周期や時間で処理を実行することができます。また、処理の負荷に応じてタスクの数を指定して処理を行うことができ、処理の終了によってタスクは自動的に削除されます。

図4:Pull Taskを使用した処理内容(クリックで拡大)

図4は連載の全体図でPull Taskの処理部分をモジュール単位で書き直した内容になっています。図でcron.xmlにはタスクの実行スケジュールが記述されており、このスケジュールにしたがってtaskcontrolServletが呼び出され、呼び出されたtaskcontrolServletが処理を実行するsptodsServletをキューに投入します。

sptodsServletはDrive上のスプレッドシートからデータを読み込んでDatastoreに書き込む処理と、書き込み完了時にその情報を関係者にメール送信する処理を行います。タスクの処理頻度やバケットサイズなどの処理能力は、queue.xmlに記述されている制約内で実行されます。

2. 2 サンプルへのPull Task機能追加

[1] web.xmlの定義とPull Task

ディプロイメントディスクリプタ(web.xml)の定義では、先頭に定義されているサーブレットからアクセスされるビーンズに、これまでの連載で見てきた処理がすべて記述されており、リスト4の(1)から後の定義はすべてPull Taskに関係するものになっています。

下記リスト4で

(1)はタスクのキュース投入を行うサーブレットの定義でcron.xmlから参照されます。
(2)はスプレッドデータのDatastore書き込み用サーブレットの定義でqueue.xmlから参照されます。
(3)はPull Queueに対するアクセス制限の指定になっています。

リスト4 war/WEB-INF/web.xml

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
    <servlet-name>spread</servlet-name>
    <servlet-class>com.google.gdata.SpreadServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>spread</servlet-name>
    <url-pattern>/spread</url-pattern>
  </servlet-mapping>
  
  <!--  (1) タスクのキュース投入を行うサーブレットの定義  -->
  <servlet>
    <servlet-name>taskcontrol</servlet-name>
    <servlet-class>com.google.gdata.taskcontrolServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>taskcontrol</servlet-name>
    <url-pattern>/cron/taskcontrol</url-pattern>
  </servlet-mapping>
 
  <!-- (2) スプレッドデータのDatastore書き込み用サーブレット定義   -->
  <servlet>
    <servlet-name>sptods</servlet-name>
    <servlet-class>com.google.gdata.sptodsServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>sptods</servlet-name>
    <url-pattern>/task/sptods</url-pattern>
  </servlet-mapping>
  
  <!--  (3) Pull Queueのアクセス制限  -->
  <security-constraint>
    <web-resource-collection>
      <url-pattern>/task/*</url-pattern>
      <url-pattern>/cron/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>admin</role-name>
    </auth-constraint>
  </security-constraint>
  
  <welcome-file-list>
    <welcome-file>index.htm</welcome-file>
  </welcome-file-list>
</web-app>

[2] cron.xmlでタスクスケジュール指定

タスクはcron.xmlファイルに記述されたスケジュールに従って実行されます。リスト5はサンプルで使用されているcron.xmlで、 WEB-INF ディレクトリ下に配置されます。

リスト5 war/WEB-INF/cron.xml

<?xml version="1.0" encoding="UTF-8"?>
<cronentries>
  <cron>
    <url>/cron/taskcontrol</url>
    <description>Write Spread data to Datastore</description>
    <schedule> every monday of month 09:00</schedule>
    <timezone>Asia/Tokyo</timezone>
  </cron> 
</cronentries>

リスト5で定義されている各タグは、それぞれ次のような意味を持ちます。

cron.xmlでスケジューリングされる制御サーブレットを指定します。サンプルのでは、web.xmlの(2)で定義されているを指しています。

scheduleタグではタスクの実行スケジュールを指定し、リスト4では毎週月曜の午前9時にタスクが実行されるように指定しています。下記のようにさまざまなパターンでタスクの実行スケジュール指定が可能です。

every 5 minutes //5分毎にタスクジョブを実行
2nd,third mon,wed of march 17:00 //3月の第2、第3月曜、水曜の17時にタスクジョブを実行
every monday of month 09:00 //月のすべての月曜9時にタスクジョブを実行
1st monday of sep,oct,nov 17:00 //8月、10月、11月の第1月曜17時にタスクジョブを実行

タスクジョブの実行を同じ間隔で繰り返し実行する場合は、
every N (hours | mins | minutes)
を使用します。ここで、N(整数)は、hours または mins(minutes) で時間の単位を指定します。
タスクを実行する最小の間隔は1分です。

以上の タグは必須で、他にオプションとしてのコメント記述とタグを指定できます。には、タイムゾーンの名前を指定します。タイムゾーンを指定しない場合は UTC(GMT)で実行されます。

[3] タスクの実行制御

Pull Taskで実行されるサーブレットは指定されたスケジュールに従って実行されるプログラムで、Webブラウザからのアクセスでは実行できないようにすべきです。 これを行っているのがリスト4の(3)にある タグ下ので、ここではWebリソースにアクセスできるロールをadminに制限しています。

[4] task制御サーブレット

リスト6  task制御サーブレット(taskcontrolServlet.java)

package com.google.gdata;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.logging.Logger;
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.TransientFailureException;
import com.google.apphosting.api.ApiProxy.ApiDeadlineExceededException;

@SuppressWarnings("serial") public class taskcontrolServlet extends HttpServlet { private static final Logger log = Logger.getLogger(sptodsServlet.class.getName()); public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { try { Queue queue = QueueFactory.getQueue("sptods"); //(1) queue.add(TaskOptions.Builder.withUrl("/task/sptods").param("sheet", "201304")); //(2) } catch (TransientFailureException e) { log.severe("{\"flag\": \"" + "TransientFailureException :" + e + "\"}"); } catch (ApiDeadlineExceededException e) { log.severe("{\"flag\": \"" + "ApiDeadlineExceededException :" + e + "\"}"); } } }

リスト6のtaskcontrolServlet.javaではPull queue にタスクを追加します。処理はシンプルで次の2つの処理を行っています。

  • (1)でqueue.xmlに定義されているキューの名前を指定してキューオブジェクト(queue)を取得する。
  • (2)次にwithUrlで指定されたサーブレットをタスクの実行プログラムとしてaddメソッドでキューに追加する。

ここでサーブレットに渡すパラメータはparamで指定することができます。

この処理でタスクはキューに追加され、次のqueue.xmlに指定された環境で実行されます。

[5] queue.xml キューの定義

タスクキューに登録するQueueは、queue.xmlで実行間隔を制御でき、サンプルではリスト7ように定義されています。

リスト7 war/WEB-INF/queue.xml

<?xml version="1.0" encoding="UTF-8"?>
<queue-entries>
  <queue>
    <name>sptods</name>
    <rate>2/m</rate>
    <bucket-size>5</bucket-size>
  </queue> 
</queue-entries>

queue.xmlで、およびはそれぞれ次の意味を持ちます。

キューの名前。リスト6 task制御サーブレットのQueueFactory.getQueue() で queue.xml を参照する時に指定される名前です。キューの名前には、文字、数字、ハイフンを使用できます。

このキューでタスクを処理する頻度で、[2/m] で指定した場合1分間に2つのキューが処理できます。値は「数字/時間の単位」の形で表します。単位は、sが秒、mが分、hが時間、dが日を表します。例えば、5/m という値は、タスクが1分あたり 5回の頻度で処理されることを意味しています。なお、数字が 0(0/s など)の場合、キューは「保留」とみなされ、タスクの処理は行われません。

バケットサイズは、数多くのタスクがキューに投入された時に、キューの処理rateを上げる上限を指定する値で、指定されていない場合のデフォルト値は5です。例えば、サンプルのようにrateが2/sでbucket-sizeが5の場合、5/sまでrateを上げることができますが、これ以上にすることはできません。

有限会社サイバースペース
慶應義塾大学工学部電気科卒。日本IBM、日本HPなどにおいて、製造装置業を中心とした業務系/基幹業務系システムのSE/マーケティングや、3階層C/Sアーキテクチャによる社内業務システム開発などに携わる。現在は、Ajax/Web 2.0関連のセミナー講師/コンサルティング、書籍執筆などを行っている。情報処理学会会員。http://www.at21.net/

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています