LoginSignup
2
3

More than 5 years have passed since last update.

Djangoでmechanizeをプーリング

Posted at

前提

DjangoでWEB APIつくって業務改善と称して社内においてまして、一部にmechanizeを使ってイントラログインとイントラの操作をAPI化して楽をしてました。

問題

WEB APIなので基本的にアクセスはステートレスでして、都度mechanizeのインスタンスを作成してイントラ操作をしています。そのため、イントラから見るとAPIへの1リクエストごとに新規ログイン状態でした。近い将来情シスに怒られるので改善したくなります。

対処

mechanizeのインスタンスを毎回作成するのではなく、プーリングすることにしました。

元々の呼び出し元
worker = IntraWorker(USER,PASS)
worker.do_something()

IntraWokerはmechanizeを使ったクラスです。__init__で毎回ログインしています。これを以下にしました。

新しい呼び出し元
# get from pool
worker = IntraWorkerPool().get(USER,PASS)
worker.do_something()
# back to pool
worker.close()

IntraWorkerPoolというクラスを追加して、これにプールを管理させます。

IntraWorkerPool
from threading import Lock

class IntraWorkerPool(object):
    """
    Mechanizeのプーリング管理

    """
    # poolされているWorker
    # user,passのタプルをキーとする
    pooled_workers = {}

    def __init__(self):
        self.lock = Lock()
    def get(self, user, password):
        """
        Workerインスタンスをプールから取り出す
        """
        ret_aw = None
        pool = IntraWorkerPool.pooled_workers
        key = (hashed(user), password)
        with self.lock:
            if key in pool:
                # 使用可能なのがなければ作る
                if len(pool[key]) == 0:
                    pool[key].append(IntraWorker(*key, pool_control=self))
            else:
                pool[key] = []
                pool[key].append(IntraWorker(*key, pool_control=self)

            # Workerがまだログイン出来る状態かチェック
            while (ret_aw is None) or (not ret_aw.is_login()):
                ret_aw = pool[key].pop()

        return ret_aw

    def back_to_pool(self, aw_inst):
        """
        poolにインスタンスを戻す
        実際はこれを直接コールしない。Worker側のcloseで呼ばせる

        """
        key = (hashed(aw_inst.user_no), aw_inst.user_password)
        pool = IntraWorkerPool.pooled_workers
        with self.lock:
            pool.setdefault(key, [])
            pool[key].append(aw_inst)

やってることは、クラス変数としてpooled_workersというディクショナリを用意してユーザ名とパスワードのタプルとWorkerインスタンスのリストの管理です。また、リスト操作はスレッドセーフにしないといけないはずなのでthreading.Lock()をつかってシリアライズしています。プールへの返却はback_to_poolというメソッドを用意し、こちらもLockで保護していますが、実際にはWorkerインスタンス側のCloseメソッド実行時にback_to_poolを実行されるようにしています。

正直、Pool管理クラスと管理対象クラスが相互依存チックなのが気に食わないのですがいまいちスマートな実装が思いつかずこんな形でお茶を濁しています。

もっとスマートなのがあればどなたか教えて頂けますと幸いです。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3