Google App Engineのデータストアは定期的にメンテナンスモードに入ります。 メンテナンス中はデータストアが読み取り専用になって一切の書き込みが禁止されます。
Python版にはCapabilityServiceというものが用意されていてこれらを調べるのは簡単ですが、Java版にはまだ用意されていないようです。
Java版で(無理せず)これをテストするには、次のようなサーブレットフィルタを用意してやります。
package com.example;
import java.io.IOException;
import java.util.concurrent.Future;
import javax.servlet.*;
import com.google.apphosting.api.ApiProxy;
import com.google.apphosting.api.ApiProxy.*;
public class MaintenanceFilter implements Filter {
@Override
public void init(FilterConfig conf) throws ServletException {
return;
}
@Override
public void destroy() {
return;
}
@Override
public void doFilter(
ServletRequest req,
ServletResponse res,
FilterChain chain) throws IOException, ServletException {
@SuppressWarnings("unchecked")
Delegate<Environment> delegate = ApiProxy.getDelegate();
try {
ApiProxy.setDelegate(new MaintenanceDelegate(delegate));
chain.doFilter(req, res);
}
finally {
ApiProxy.setDelegate(delegate);
}
}
private static class MaintenanceDelegate implements Delegate<Environment> {
private final Delegate<Environment> delegate;
MaintenanceDelegate(Delegate<Environment> delegate) {
this.delegate = delegate;
}
@Override
public void log(Environment env, LogRecord record) {
this.delegate.log(env, record);
}
@Override
public Future<byte[]> makeAsyncCall(
Environment env,
String service,
String method,
byte[] bytes,
ApiConfig config) {
return this.delegate.makeAsyncCall(env, service, method, bytes, config);
}
@Override
public byte[] makeSyncCall(
Environment env,
String service,
String method,
byte[] bytes) throws ApiProxyException {
if (service.equals("datastore_v3")) {
if (method.equals("Put") || method.equals("Delete")) {
throw new CapabilityDisabledException(service, method);
}
}
return this.delegate.makeSyncCall(env, service, method, bytes);
}
}
}
これをweb.xmlに登録します。このとき、「/_ah/」以下をフィルタするといろいろ不具合が発生するので、必要最小限にしましょう。
<filter>
<filter-name>MaintenanceFilter</filter-name>
<filter-class>com.gluegent.goose.soc.front.util.MaintenanceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MaintenanceFilter</filter-name>
<url-pattern>/gadget/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
このフィルタを経由した状態でデータストアに書き込みを行うと、CapabilityDisabledExceptionがスローされるようになります。 例外をキャッチしてメンテナンス中の処理を書いておきましょう。
try {
// データストアへの書き込み
}
catch (CapabilityDisabledException e) {
// メンテナンス中の処理
}
メンテナンスモードのときの動作がエミュレーションされるので、この状態で様々なテストを実施します。 なお、このフィルタを残したままサービスインするとひどいことになります。
追記
ご指摘いただきました。 メンテナンスモードのときはDatastoreService.allocateIds()やMemcacheなども動かなくなるので、makeSyncCallメソッドの中でもう少しトラップが必要です。 具体的にはこんな感じ:
@Override
public byte[] makeSyncCall(
Environment env,
String service,
String method,
byte[] bytes) throws ApiProxyException {
if (service.equals("datastore_v3")) {
if (method.equals("Put") ||
method.equals("Delete") ||
method.equals("AllocateIds")) {
throw new CapabilityDisabledException(service, method);
}
}
else if (service.equals("memcache")) {
throw new CapabilityDisabledException(service, method);
}
return this.delegate.makeSyncCall(env, service, method, bytes);
}



0 コメント:
コメントを投稿