修行の場

知人が言っていました。これは修行だと。

ゆるふわにMongoDBを使う

ゆるふわにMongoDBを使う

背景

プロダクトではなく、分析やプロト開発のためにMongoDBを使う場合、 楽に導入し、できるだけ設定せず使いたいです。(分析コードやプロトを他人と共有する場合は特に)

MongoDBの導入

環境:Ubuntu18.04 condaでインストールできるのでcondaで導入します。

DBPATH=~/mongo_test/db

conda install mongodb -y
conda install pymongo -y

mkdir -p $DBPATH
mongod --dbpath $DBPATH

monogo
# > try some command

という感じで導入と導入確認はできます。

明示的にmongodbの立ち上げする必要をなくす

もはやmongodの立ち上げすらしたくないので、 pymongo.MongoClient利用時にmongodが起動していなければ自動的に起動するようなメソッドを作理、すべてのMongoClientはここから取得するようにします。終了はOS終了時に行われる想定で。

このようにして、このモジュールを常に使えばそのシステム内で初めて使った場合に必ず実行されるようになります。

import fcntl
import os
import shlex
import subprocess
import time

import pymongo
from pymongo.errors import ConnectionFailure

_DEFAULT_MONGO_PORT = 20090
_DB_PATH = os.path.expanduser("~/.local_mongo/db")
_RETRY_MAX = 5
_TIMEOUT_MS = 300

def get_local_mongo_client_with_server_preperation(port=None):
    try_count = 0
    while try_count < _RETRY_MAX:
        x = open('/tmp/local_mongo.lock', 'w+')
        fcntl.flock(x, fcntl.LOCK_EX)
        client = pymongo.MongoClient(port=_DEFAULT_MONGO_PORT, connectTimeoutMS=_TIMEOUT_MS, serverSelectionTimeoutMS=_TIMEOUT_MS)
        try:
            client.admin.command('ismaster')
            break
        except ConnectionFailure:
            os.makedirs(_DB_PATH, exist_ok=True)
            subprocess.Popen(shlex.split(f"mongod --dbpath {_DB_PATH} --port {_DEFAULT_MONGO_PORT}"), 
                stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        fcntl.flock(x, fcntl.LOCK_UN)

        try_count += 1
        time.sleep(0.5)
    return client