AppsスプレッドシートとApp Engineのデータ交換を完成させる
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の処理部分をモジュール単位で書き直した内容になっています。図で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でスケジューリングされる制御サーブレットを指定します。サンプルの
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分です。
以上の
[3] タスクの実行制御
Pull Taskで実行されるサーブレットは指定されたスケジュールに従って実行されるプログラムで、Webブラウザからのアクセスでは実行できないようにすべきです。 これを行っているのがリスト4の(3)にある
[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を上げることができますが、これ以上にすることはできません。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- AppsのスプレッドシートデータをApp Engineから読み取る
- App Engineから読み取ったデータの書き込みと、スプレッドシートのUIで表示する処理
- Google AppとApp Engineの準備・設定を完了する
- JDO APIとLow-Level APIの違いと基本CRUD処理
- クラウドをより身近に!Google Driveを使った業務データ移行入門
- 同一テーブルでプロパティ項目を変更して永続化
- FirebaseプログラムをApp Engineにディプロイする
- エンティティ所有/被所有関係とトランザクション処理
- リスト・プロパティを含むエンティティの永続化
- Google Driveと Cloud DatastoreのデータをBigQueryで使用する