07.Google App Engineのデータストアを自動バックアップする方法 | CA Beat エンジニアのブログ

CA Beat エンジニアのブログ

Google App Engineをメインに技術情報を発信しています。

$CA Beat エンジニアのブログ-App Engine デフォルト


CA Beat エンジニアリーダーのヤマサキ(@vierjp)です。
急に寒くなってきましたが、皆様体調に気をつけていきましょう(`・ω・´)


前回の予告どおり、今回は「Datastoreの自動バックアップ」についてです。



○公式ドキュメント通りの自動バックアップ

Datastoreのバックアップは公式ドキュメントに書かれている通り、
以下のようにcronを設定すれば自動化できます。



<?xml version="1.0" encoding="UTF-8"?>
<cronentries>
<cron>
<url>/_ah/datastore_admin/backup.create?name=BackupToCloud&kind=LogTitle&kind=EventLog&filesystem=gs&gs_bucket_name=whitsend</url>
<description>My Daily Backup</description>
<schedule>every 12 hours</schedule>
<target>ah-builtin-python-bundle</target>
</cron>
</cronentries>



参考:Scheduled Backups - Google App Engine — Google Developers

このようにcronからバックアップした場合も手動で実行した場合と同様に
Datastore Adminの「Backups」の一覧にバックアップデータが表示されるので、
手動でバックアップした場合と同様にリストアすることができます。

ただ、この方法はKindが増えた際にcronのパラメーターを毎回追加する必要があって面倒ですし、
運用上の問題としてKind名の追加し忘れリスクもあります。


そこで、



○Kind名指定不要な自動バックアップ

Low Level APIだけ使ってコーディングする場合はSlim3のModelクラスに該当するクラスは無いので
前述のようにパラメーターで一つずつ指定する必要があるのでしょうが、
Slim3を使用している場合にはKind名に対応するModelクラスが存在します。
そこでバックアップ対象のKind名を存在するSlim3のModelクラスから自動で取得するようにしました。

その上で、cronから直接「/_ah/datastore_admin/backup.create」を呼ぶのではなく、
「『/_ah/datastore_admin/backup.create』をTaskとしてTask Queueに登録するServlet」を作成して、
作成したServletをcronから実行するようにします。

・Servletから抜粋



Queue queue = QueueFactory.getDefaultQueue();
TaskOptions t = TaskOptions.Builder.withUrl("/_ah/datastore_admin/backup.create");
t.param("name", exeBackupName);
t.param("queue", exeQueueName);

// add kinds.
List modelNames = findModelNames();
if (modelNames.size() == 0) {
throw new IllegalStateException("Model name list not found.");
}
for (String model : modelNames) {
t.param("kind", model);
}

t.param("filesystem", "gs");
t.param("gs_bucket_name", exeBucketName);
t.method(Method.GET);
t.header("Host", BackendServiceFactory.getBackendService().getBackendAddress("ah-builtin-python-bundle"));

queue.add(t);


// 以下Kind名取得処理

private List findModelNames() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
String modelPackagePath = modelPackage.replace('.', '/');
List modelNames = new ArrayList();
try {
Enumeration resources = classLoader.getResources(modelPackagePath);
List dirs = new ArrayList();
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
dirs.add(new File(resource.getFile()));
}

for (File directory : dirs) {
modelNames.addAll(fetchNames(directory));
}
} catch (IOException e) {
throw new IllegalStateException(e);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e);
}

Collections.sort(modelNames);

return modelNames;
}

private List fetchNames(File directory) throws ClassNotFoundException {
List modelNames = new ArrayList();
if (directory.exists()==false) {
return modelNames;
}
File[] files = directory.listFiles();
for (File file : files) {
if (file.getName().endsWith(".class")) {
String modelName = file.getName().replaceFirst("\\..*$", "");
Class clazz = Class.forName(modelPackage + "." + modelName);
Annotation annotationModel = clazz.getAnnotation(Model.class);

if (annotationModel != null) {
modelNames.add(modelName);
}
}
}
return modelNames;
}




・cron.xmlの記述



<?xml version="1.0" encoding="UTF-8"?>
<cronentries>
<cron>
<url>/datastore_backup</url>
<description>My Daily Backup</description>
<schedule>every 12 hours</schedule>
</cron>
</cronentries>



上記コードはSlim3のModelアノテーションをチェックして「Modelクラスである事」を確認しているので
Slim3を使っている場合にしか使えませんが、
Kind名に対応するクラスが存在するなら他のフレームワークを使っている場合でも少しの修正で動くと思います。

必要な変数はweb.xmlからServletのInitパラメーターで指定するか、
cron.xmlからリクエストパラメーターで指定します。
(上の例ではServletのInitパラメーターを指定しているためcron.xmlでのパラメーター指定は無しです)

上記はソースコードの一部ですが、動いているコードから抜粋したものです。


これで使用するKindを追加した場合でも、
cron.xmlの設定変更無しで次回からのバックアップ対象に追加されるようになりました。

手間とヒューマンエラーを減らすための自動化、地味かもしれませんが大事です。


それではまた次回お会いしましょう!(`・ω・´)ゞ


★宣伝★
CA BeatではTwitter、Facebookページの運営も行っております!
ブログの更新情報だけでなく、役立つスマホトピックニュースを
選りすぐって配信中♪

ブログ右サイドバーからぜひフォロー、いいね!してくださいねヽ(´▽`)ノ


この記事をはてなブックマークに追加



★宣伝★
CA BeatではTwitter、Facebookページの運営も行っております!
ブログの更新情報だけでなく、役立つスマホトピックニュースを
選りすぐって配信しております。

ブログ右サイドバーからぜひフォロー、いいね!してくださいねヽ(´▽`)ノ