search
LoginSignup
0

More than 5 years have passed since last update.

posted at

Write your blackbird plugin #003

blackbird pluginを書こう第三弾ってことで、第二弾で細かく書けなかったところ、主に

  • JobBaseの各メンバプロパティについて
    • queueとか
    • loggingとか
  • 各基底クラス側で実装されている便利関数について
    • こちらは落穂拾い的な内容になると思います

ではどどーんと逝きましょう。

About each member properties of JobBase class

self.options

こちらは第二弾でも説明させていただきましたが、コンフィグファイルに記載した内容をkeyとvalueとして解釈して、
dictionary形式にしたものです。具体的には

[SECTION_NAME_IS_ANYTHING_OK]
hostname = hogehoge.com
hogehoge = fugafuga

みたいなコンフィグファイルがあったら、

self.options = {
    'hostname': 'hogehoge.com',
    'hogehoge': 'fugafuga'
}

みたいな感じのdictionaryが出来上がります。ここについては第二弾でも結構詳しく書いたつもりなので、
こんな感じです。もっとkwsk!ってのがあればコメントか僕宛にコンタクトを取ってもらえれば書かせていただこうかなと思います。

self.queue

MainのプロセスがThread間でメッセージをやりとりする用のQueueです。特に難しいことはしてなくって、
Python謹製のQueue.Queueをそのまま使ってます。
なので、self.queue.putメソッドはそのままQueue.Queue.putを読んでいるものと同じだと考えてくださいまし。

notes:

putメソッドについてですが(プラグインを書く人は主にputメソッドを使うことになると思ってます)、
blockという引数があって自分がput操作をしているときは他のConsumer及びProducerからの操作を
blockするというものです。
しかし、こちらはひとつのItemに対してkey, clock, hostがかぶることはないという条件のもと、
block=Falseを強く推奨しています

self.logger

ロギング用のインスタンスです。このインスタンスはPython謹製のloggingモジュールを出力フォーマットだけ変更しただけのものになるので、
loggingモジュールのメソッドがそのまま使用可能です。

self.logger.debut('This is Debug log!! HOGEHOGE!!!!!!!!!!')

そのため上記のように書くことも可能です。ログの出力レベルですが、defaultではWARNです(こちらはglobalセクションで変更が可能です)。

self.invalid_key_list

//今更ですがちょっとプロパティ名、ミスってるかなって気もしてますwww
//invalidじゃないなーって感じw ignoreとか??

こちらは、Itemのkeyがこのlistの中に存在している場合、Queueに入れないっていうブラックリストです。
たとえば、

class ConcreteJob(blackbird.plugins.base.JobBase):

    def __init__(self, options, queue=None, logger=None):
        super(ConcreteJob, self).__init__(options, queue, logger)
        self.invalid_key_list = [
            'host.IGNORE_KEY_NAME001',
            'host.IGNORE_KEY_NAME002'
        ]

ってかけば、某memcachedのstatsコマンドのようなまるっと取ってくるってところに振り分け処理を書かずにロジックを別のメソッドに切り出すことが可能になります。
この場合、listに勝手に入れるだけではもちろんダメでございまして、

#..snip..

def filter_item(item):
    if not item.data['key'] in self.invalid_key_list:
        return item

def filter_items(items):
    filtered_items = list()
    for entry in items:
        if not items.data.['key'] in self.invalid_key_list:
            filtered_items.append(entry)

    return filtered_items

的にいい感じで実装してもらえればと思います。

各基底クラス側で実装されている便利関数について

続きまして、各基底クラス側で実装されている便利関数についてです。
まぁ、正直多くはありませんが、それなりにプラグインづくりを手助けしてくれるとは思います。

blackbird.plugins.base.ValidatorBase.detect_hostname

名前の通りhostnameを取ってくるようなメソッドです。
低レイヤーな関数を使っているのですが(Pythonはこういうのがさらっと使えるのがいいですね)、その実すごいシンプルで、

return socket.getfqdn() or socket.gethostname() or 'localhost'

ってやってるだけです。

  1. socket.getfqdn()の結果があれば、それをそのままreturn
  2. なければsocket.gethostname() (short hostname、hostname -sの結果ですね)をreturn
  3. それもダメならlocalhostを文字列として返すってかんじですね。

使いドコロとしては、

class Validator(base.ValidatorBase):
    def __init__(self):
        self.__spec = None

    @property
    def spec(self):
        self.__spec = (
            "[{0}]".format(__name__),
            "hostname = string(default={0})".format(self.detect_hostname()),
        )
        return self.__spec

こんなところですかね。ちなみにここは大先輩の提案により実装されたものでありまして、この場を借りましてありがとうございますですm(_ _)m

Timer context

Timer contextはwithでくくったコンテキスト内の処理時間を測定するcontextです。
僕たちはredisやmemcachedへのkeyの書き込みや読み込みに使ってratencyを測定してMetricにしてます。
使い方は普通のContextとなんにもかわんなくって、

import blackbird.plugins.base.Timer

with Timer() as timer:
    for entry in xrange(0, 9):
        print entry

    return [timer.sec, timer.msec]

とかってやれば、timerクラスのsecプロパティが処理時間を秒(seconds)で返して、
msecプロパティが処理時間をミリ秒(mill seconds)で返してくれます。

About Blabckbird Exception

Exception(ここでいう本当の意味でのってのは、あなたのプラグインに予期せぬエラーが発生したときのExceptionって意味ですね)が
発生した時に予期せぬものなのか、それとも意図的にraise ValueErrorのように発生させられたものなのかを区別するために、
独自のExceptionを実装してあります。
といっても、エラー文字列を指定してraiseするだけなので、ValueErrorとかとまったく同じ方法でraiseします。たとえば、

import blackbird.plugins.base.BlackbirdPluginError

try:
    value = self.options['key']
except KeyError as exception:
    raise blackbird.plugins.base.BlackbirdPluginError(
        exception.__str__
    )

とすることで、Exceptionを吐いた時の挙動をdebuggingしやすくします。


blackbird.plugins.baseモジュール側でやってることってこんなもんなんですが、
ここがわかんねーよとか、ここは違うんじゃねとか、こういうメソッドがbase側にも欲しいみたいなのが
ありましたらどんどん教えてもらえればなーと考えておりますm(_ _)m

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
What you can do with signing up
0