gen_eventの抂芁アカりント倉曎通知

翻蚳者から私はカルマの欠劂のために結び付けられた旗をキャッチしようずしたすずころで、最初の翻蚳に感謝したす。著者のおかげで、著者の䞀連の蚘事を翻蚳し続けたいず思いたす。



前の郚分ぞのリンクは、蚘事の最埌にありたす。



これは、 OTPシリヌズの抂芁の 3番目の蚘事です。 最初のパヌトから始めるこずをお勧めしたす。これは、gen_serverに぀いお説明し、銀行システムの基瀎を築きたすただ行っおいない堎合。 䞀方、有胜な孊生であれば、既補のモゞュヌルeb_atm.erlおよびeb_server.erlを芋るこずができたす。



シナリオ 䞭倮サヌバヌ゜フトりェアずロヌカルATMの出珟により、ErlyBankは技術ベヌスを楜芳的に認識し始めたした。 しかし、競合他瀟に察する保護手段ずしお、䞀定量の珟金が匕き出されたずきに通知を送信するシステムを実装したいず考えおいたす。 ゜フトりェアを再起動せずに、珟金匕き出し額のしきい倀を倉曎するず、通知がトリガヌされたす。 経営陣は、タスクに埓っお珟圚のバヌゞョンをアップグレヌドするために私たちを雇うこずにしたした。



結果  gen_eventを䜿甚しおむベントベヌスの通知システムを䜜成したす。 これにより、将来的に他の通知を䜜成するための基本的な基盀が提䟛されるず同時に、珟圚のサヌバヌ゜フトりェアぞの統合が容易になりたす。



gen_eventずは䜕ですか



gen_eventは、Erlang / OTPの動䜜モゞュヌルずしお機胜したす 動䜜;前の著者の翻蚳ずは異なる甚語を䜿甚したす。サむクルの初期に、甚語は「むンタヌフェむス」ずしお翻蚳されたした。トランスレヌタ むベント凊理機胜を実装したす。 これは、倚くのハンドラヌが実行されおいるむベントマネヌゞャヌプロセスを実行するこずで実珟されたす。 むベントマネヌゞャヌは他のプロセスからむベントを受信し、各ハンドラヌは順番にむベント通知を受信し、それらで䜕でもできたす。



ハンドラヌの予想されるコヌルバックは次のずおりです。



このシリヌズの前半で説明した2぀の動䜜モゞュヌルず比范しお、珟圚のモゞュヌルには比范的少数のフィヌドバックメ゜ッドがありたす。 ただし、gen_eventは同じ頻床で䜿甚でき、他のOTPモゞュヌルず同じ機胜を備えおいたす。



むベントマネヌゞャヌを䜜成する



最初に行う必芁があるのは、むベントマネヌゞャヌを䜜成するこずです。 これは比范的簡単なタスクです。gen_eventサヌバヌを起動するだけであり、いく぀かのAPIメ゜ッドを远加するこずで、新しいハンドラヌの远加、通知の送信などが簡単になりたす。



私のむベントマネヌゞャヌフレヌムワヌクを芋おください。 さらに、基瀎ずしお䜿甚しお、フラグメントを提䟛したす。



ご芧のずおり、このファむルは珍しいものではありたせん。 開始方法は、他のOTP動䜜モゞュヌルず同じです。 むベントマネヌゞャヌにハンドラヌを远加するメむンAPIを含めたした。

%%--------------------------------------------------------------------

%% Function: add_handler(Module) -> ok | {'EXIT',Reason} | term()

%% Description: Adds an event handler

%%--------------------------------------------------------------------

add_handler(Module) ->

gen_event:add_handler(?SERVER, Module, []).







このメ゜ッドは、単に珟圚のモゞュヌルにあるむベントハンドラヌをむベントマネヌゞャヌに远加したす。 たた、むベントマネヌゞャヌを介しお通知を送信するために必芁な、䜿いやすいメ゜ッドを远加したした。

%%--------------------------------------------------------------------

%% Function: notify(Event) -> ok | {error, Reason}

%% Description: Sends the Event through the event manager.

%%--------------------------------------------------------------------

notify(Event) ->

gen_event:notify(?SERVER, Event).







たた、理解しやすいものでなければなりたせん。 このメ゜ッドは、むベントをむベントマネヌゞャに送信するだけです。 gen_eventnotify / 2は非同期芁求であるため、すぐに戻りが発生したす。



むベントマネヌゞャヌをサヌバヌに接続する



サヌバヌが起動する前に、むベントマネヌゞャヌが既に実行されおいるこずを確認したいので、サヌバヌモゞュヌルから明瀺的に起動するように匷制したす。 埌で、別の蚘事で、 スヌパヌバむザヌツリヌにこれを匷制する予定です。 新しいサヌバヌ初期化コヌドは次のずおりです。



init([]) ->

eb_event_manager:start_link(),

{ok, dict:new()}.









むベントマネヌゞャヌはサヌバヌプロセスの党期間を通じお起動されるこずを前提ずしおいるため、特定の時点でメッセヌゞを送信するこずができたす。 クラむアントであるErlyBank は、䞀定の額の匕き出しがい぀発生するかを知りたいず考えおいたす 著者は入金、぀たり入金ず蚀いたすが、これは明らかに間違いです。 これは私がこれをサヌバヌに接続する方法です



handle_call({withdraw, Name, Amount}, _From, State) ->

case dict:find(Name, State) of

{ok, {_PIN, Value}} when Value < Amount ->

{reply, {error, not_enough_funds}, State};

{ok, {PIN, Value}} ->

NewBalance = Value - Amount,

NewState = dict:store(Name, {PIN, NewBalance}, State),

% Send notification

eb_event_manager:notify({withdraw, Name, Amount, NewBalance}),

{reply, {ok, NewBalance}, NewState};

error ->

{reply, {error, account_does_not_exist}, State}

end;









これで、むベントマネヌゞャを䜿甚した匕き出し䞭に、むベントも生成されたす。 通知メ゜ッドは非同期であり、むベントマネヌゞャヌずハンドラヌは別々のプロセスで実行されるこずに泚意しおください。 これは、通知が䞊行しお実行され、トランザクションの速床が䜎䞋しないこずを意味したす。 もちろん、プロセッサが過負荷になるず、各プロセスの実行に時間がかかりたすが、理論的には同時に発生するはずです。



たた、ここで匕き出し金額が特定の金額を超えたかどうかをチェックしおいたせん。 ErlyBankは、しきい倀ずしお䜿甚する量を指定したせんでした。サヌバヌプロセスでハヌドコヌディングするのはかなりばかげおいたす。 䞀般に、すべおのロゞックをハンドラヌに残しお、通知を呌び出すこずをお勧めしたす。 そしお、これはたさに私たちが次にするこずです



eb_server.erlのすべおのコンテンツはここで芋るこずができたす 。



ハンドラヌフレヌム



私はい぀もすべおのOTPモゞュヌルの基本的なフレヌムワヌクを持っおいたす。 むベントハンドラヌに぀いおはこちらをご芧ください 。



このモゞュヌルを際立たせおいる1぀のこずここにはstart_linkたたはstartメ゜ッドがありたせん。 これは、むベントハンドラヌを接続するためにeb_event_manageradd_handlerModuleメ゜ッドを䜿甚しおいるためです。実際、このメ゜ッドはプロセスを開始しお生成したす。



init([]) ->

{ok, 500}.









gen_eventハンドラヌの初期化メ゜ッドは、他のすべおのErlang / OTP動䜜モゞュヌルのメ゜ッドず䌌おいたすが、 {ok、State}を返したす。Stateはプロセスのデヌタの状態です。 この堎合、500を返したす。これは、アカりントからの匕き出しの通知の譊告しきい倀を瀺すために䜿甚したす。



珟金匕き出し通知凊理



このむベントハンドラヌの唯䞀の目的は、出金通知を受け入れ、出金額が特定のしきい倀を超えた堎合に䜕かを行うこずです。 むベントは、非同期メッセヌゞgen_eventnotify / 2を䜿甚しおディスパッチされたす。 ハンドラヌぞの非同期通知は、 handle_eventメ゜ッドによっお凊理されたす。



handle_event({withdraw, Name, Amount, NewBalance}, State) when Amount >= State ->

io:format("WITHDRAWAL NOTIFICATION: ~p withdrew ~p leaving ~p left.~n", [Name, Amount, NewBalance]),

{ok, State};

handle_event(_Event, State) ->

{ok, State}.









メッセヌゞの凊理は簡単です。 しきい倀の撀回の量を超えた堎合にのみむベントを受信するために、撀回メッセヌゞず保護を確認するためのテンプレヌトを远加したした。



匕き出し金額がしきい倀を超えるず、端末に出力したす。



完成したeb_withdrawal_handler.erlモゞュヌルは、 ここで取埗できたす 。



操䜜䞭のしきい倀の倉曎



ErlyBankは、仕事䞭に珟金の匕き出しを通知するためのしきい倀を倉曎できるようにしたいずも述べたした。 これを行うには、実際のハンドラヌにAPIメ゜ッドを远加したす。 ここにありたす



%%--------------------------------------------------------------------

%% Function: change_threshold(Amount) -> {ok, Old, NewThreshold}

%% | {error, Reason}

%% Description: Changes the withdrawal amount threshold during runtime

%%--------------------------------------------------------------------

change_threshold(Amount) ->

gen_event:call(eb_event_manager, ?MODULE, {change_threshold, Amount}).









これにより、新しいget_eventメ゜ッドであるcallメ゜ッドが導入されたす。 このメ゜ッドは、特定のハンドラヌに芁求を送信し、応答を予期するため、同期的です。 圌の匕数はcallEventManager、Handler、Messageです。 したがっお、この堎合、最初のパラメヌタヌずしお、珟圚のプロセスに登録されおいるむベントマネヌゞャヌモゞュヌルを瀺したす。 ハンドラヌモゞュヌルの名前を2番目のパラメヌタヌずしお指定し、しきい倀を倉曎するメッセヌゞを送信したす。



このリク゚ストは、 handle_call / 2フィヌドバックメ゜ッドで凊理したす。



handle_call({change_threshold, Amount}, State) ->

io:format("NOTICE: Changing withdrawal threshold from ~p to ~p~n", [State, Amount]),

{ok, {ok, State, Amount}, Amount};

handle_call(_Request, State) ->

Reply = ok,

{ok, Reply, State}.









たず、しきい倀が倉曎されおいるずいうメッセヌゞを端末に衚瀺し、次にメッセヌゞ{ok、OldThreshold、NewThreshold}で返信し、新しいしきい倀をデヌタの状態ずしお蚭定したす。 次の出金通知を受け取るず、ハンドラヌは新しい譊告倀を䜿甚したす :)



完党なeb_withdrawal_handlerモゞュヌルは、 ここで衚瀺できたす 。



おわりに



gen_eventに関するこの蚘事では、むベントマネヌゞャヌの䜜成、むベントのディスパッチ、むベントハンドラヌの実装、これらのむベントの受信、およびハンドラヌの呌び出しに぀いお説明したした。 私が開瀺しなかった唯䞀のこずは、gen_eventの䞀郚です。これにより、むベントハンドラヌは切断したり、別のハンドラヌに眮き換えたりできたす。 その理由は、私は実際の環境でこのメカニズムを䜿甚した経隓が豊富ではないからです。 これたでのずころ、私はこれらの機䌚ぞの応甚を芋぀けおいたせん。 ただし、それらに぀いお知りたい堎合は、 ドキュメントを参照しおください。



これで、Erlang / OTP導入サむクルの3番目の郚分が終了したす。 第4条は数日䞭に公開される予定で、 監督者に぀いお話したす。






UPD

kutu habrayuzerの泚意のおかげで、重倧な省略が発芋されたした。これは、原文で䜜成され、その埌翻蚳に移行したした。 泚この蚘事では、ハンドラヌに察しおeb_event_manageradd_handlerModuleを呌び出す必芁がある堎所を瀺しおいたせん。 呌び出しは実行されないため、ハンドラヌは䜜業に含たれたせん。 この段階でハンドラヌを接続する論理的な堎所は、eb_serverl.erlのinitArgsです。 これは、必芁な倉曎を行った埌のこのメ゜ッドの倖芳です。



init([]) ->

eb_event_manager:start_link(),

eb_event_manager:add_handler(eb_withdrawal_handler),

{ok, dict:new()}.









将来の蚘事では、元のテキストの䜜成者は、すべおの起動スクリプトを1か所から起動するこずを玄束したすが、これは次の蚘事でのみ発生したす。 私たちず䞀緒にいおください



さらに、eb_withdrawal_handlerハンドラヌの完党版ぞのリンクが翻蚳に远加されたしたが、誀っお持っお行くのを忘れおいたした。




シリヌズの蚘事


4. コントロヌラヌを䜿甚しおErlyBankをフロヌト状態に保぀

3. gen_eventの抂芁請求曞倉曎の通知珟圚の蚘事



翻蚳の著者は関係者です

2. gen_fsmの抂芁ErlyBank ATM

1. gen_serverの抂芁ErlyBank

0. Open Telecom Platform / Open Telecommunication PlatformOTP / OTPの抂芁

-1。 背景



All Articles