Google App Engineでは、セッション情報はデータストアに保存されます。
で、自動的には消えないので、うかうかするとこんなふうに100万件以上たまってしまいます。
容量もそれなりに食って、350MB近くになっていました。GAEでは1GBを超えると課金されるので、この容量は痛い。
ということで、セッション情報を消す処理を書いてみました。あとは、これを手動で呼び出すもよし、CRONで定期的に呼び出すもよし。
あと、ここのlogメソッドのようなものは、どっか書いとくとログを自分のUIで好きに見れるようにできるので便利。これも定期的にまとめたり消したりする処理必要になりますが。
というか、データ全部消す処理って、どう書くのが一番いいんでしょう?なんかすげー時間かかってるんですけど。
※ shin1ogawaさんに「makeSyncCallサーブレットを立てて、ローカルのプログラムからバッチ削除する方が手っ取り早い」「日付とか関係なしに削除、ログの出力も不要、なら標準でSessionCleanupServletってのもあります」と教えてもらった(16:55)
public class SessionClearServlet extends HttpServlet { public static void log(String category, String level, String message){ DatastoreService ds = DatastoreServiceFactory.getDatastoreService(); Entity ent = new Entity("Log"); ent.setProperty("c", category); ent.setProperty("l", level); ent.setProperty("m", message); ent.setProperty("d", new Date()); ds.put(ent); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //消去用タスクをキューにいれる Queue queue = QueueFactory.getDefaultQueue(); queue.add(TaskOptions.Builder.url("/queue/sessionclear")); log(SessionClearServlet.class.getSimpleName(), "info", "セッションログ消去開始"); response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("queued"); out.close(); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //実際の消去処理開始 long now = new Date().getTime() / (60 * 60 * 1000); now *= (60 * 60 * 1000); DatastoreService ds = DatastoreServiceFactory.getDatastoreService(); Query entq = new Query("_ah_SESSION") .addSort("_expires", Query.SortDirection.ASCENDING) .addFilter("_expires", Query.FilterOperator.LESS_THAN, now); //開始ログ Iterator<Entity> firstIte = ds.prepare(entq).asIterator(FetchOptions.Builder.withLimit(1)); if(firstIte.hasNext()){ Date s = new Date((Long)firstIte.next().getProperty("_expires")); log(SessionClearServlet.class.getSimpleName(), "info", s.toString()); //セッション消去開始 Query q = entq .setKeysOnly(); for(;;){ List<Entity> ents = ds.prepare(q).asList(FetchOptions.Builder.withLimit(200)); if(ents == null || ents.size() == 0) break; List<Key> keys = new ArrayList<Key>(); for(Entity ent : ents) keys.add(ent.getKey()); ds.delete(keys); } } log(SessionClearServlet.class.getSimpleName(), "info", "セッションログ消去終了"); } }