indexの更新遅延を考慮した実装を行う
実はバリデータ関係でちょっと問題があったりしますこれは会議室の名前の重複をチェックするバリデータですが、appengine固有の問題により正常に動きません。ユニットテストでも問題ないため最悪本番稼動した後に発覚する一番質の悪いバグですね。これに関してはまた別の機会に書きます。(これはappengineで何らかのサービスを運営してしてないと気づかないかなぁと)
前回のブログでこんなことを書いてましたが解答編です。タイトルにもあるように、インデックスの更新遅延が原因でバリデータは正常に動きません。(appengineじゃなかったらこういう問題はおきないんですがねw)
Entity自体はすぐにDatastoreに反映されるのですが、indexの更新には若干ラグがあります。厳密に調べたことはありませんがひどい時で1?2時間くらいindexが更新されなかったことがあります。
検索系は多少古い検索結果が返ってくることを許容することでいけますが、データの整合性に関してはそうもいきません。
例えば今回の場合だと登録するタイミングによっては同一名の会議室が存在する可能性があります。
よってindexやqureyを利用しない重複チェックを使用することになります。解決方法としては2つあります
1. keyに会議室の名前を入れる
keyはuniqueなのでこれがベストですね
2. Datastore.putUniqueValueを利用する
keyを利用するのがベストなんですが、運用中で容易にkeyを変えられないという場合があります。また、key以外の要素でもuniqueな要素を持たせたいというのはあると思います。
そういう場合はSlim3のDatastore.putUniqueValueを利用するのがいいですこれはソースを見ててたまたま見つけたやつなんですが、uniqueな名前を管理するためのEntityを1つ作ってしまうというやり方です。valueをDatastoreのkeyにしているので原理的には1と全く同じです。
サンプルコード
import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import org.junit.Test; import org.slim3.datastore.Datastore; import org.slim3.tester.AppEngineTestCase; public class PutUniqueValueTest extends AppEngineTestCase{ private static final String UNIQUE_INDEX_NAME = "ConferenceRoomName"; @Test public void test() throws Exception { boolean actual1 = Datastore.putUniqueValue(UNIQUE_INDEX_NAME, "会議室A"); assertThat(actual1, is(true)); // 重複登録しようとするとfalseが返却される boolean actual2 = Datastore.putUniqueValue(UNIQUE_INDEX_NAME, "会議室A"); assertThat(actual2, is(false)); assertThat(tester.count(UNIQUE_INDEX_NAME), is(1)); } }