21
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ConsoleAppFramework(旧MicroBatchFramework)を用いたAzure Functionsの実装例と良いところ紹介

Last updated at Posted at 2019-04-13

とのことで記事修正しました。

#はじめに
ConsoleAppFrameworkを用いてAzure Functionsにアプリをデプロイしてみたのでその方法を紹介し、ConsoleAppFrameworkの良いところについても記載してみます。

##ConsoleAppFrameworkとは

詳細は上記参照なのですが、GUIを作成するためのフレームワークとしてPrism等があるように、CUIを作成する際にもフレームワークを用いましょうという感じです。

#ざっくりやりたいこと
image.png

上図のように(定期的に)ネット上から情報取得して整形フィルタリングしてネット上のどこかに出力(通知)したいなと考えていました。
情報元の数だけコンソールアプリケーション(バッチスクリプト)を用意してcronにでも仕掛ければ実現できる内容です。

#ConsoleAppFrameworkを採用した理由
MicroBatchFramework – クラウドネイティブ時代のC#バッチフレームワークから引用

すでにC#にはコマンドライン引数の解析ツールはたくさんあります。とはいえ、そもそもそういうツールを使う時は「コマンドライン引数の解析」がしたいわけではなくて、「パラメータバインディング」をしたいのが一般的と思われます。ということで、『MicroBatchFramework』はウェブフレームワークのようにメソッドを呼び出してくれる仕様にしました。

という点にとても共感しました。これを用いればひとつのコンソールアプリケーションで複数のユースケースを使い分けられると思いました。

##ざっくりエントリーポイントの紹介

using ConsoleAppFramework;
using Microsoft.Extensions.Hosting;

class Program
{
    public static async Task Main(string[] args)
    {
            await Host
                .CreateDefaultBuilder()
                .RunConsoleAppFrameworkAsync(args);
    }
}

コンソールアプリのエントリーポイントに上記内容を記述するだけで使えます。

#サーバーレスアーキテクチャへの変更
cronのためだけにサーバを起動し続けるのももったいないのでサーバーレスアーキテクチャを採用してみることにしました。
Azure Logic Appsの繰り返しトリガーHttpトリガーのAzure Functionの組み合わせでcronちっくことが実現できました。
デザイナーで見ると
image.png
こんな感じでjsonでコンソールアプリケーションに入力する内容を伝えれば済みます。

##Azure Function例

    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            await Program.Main(new[] { (string)req.Query["exec"] });

            return (ActionResult)new OkObjectResult("OK");
        }
    }

コンソールアプリケーションといってもエントリーポイントは文字列配列を引数としたstaticメソッドなので外部から呼び出せます。
jsonで取得した情報を文字列配列に置きなおしてキックすれば動きます。
これの何がすごいかって、実装やテストはコンソールアプリケーションで行ってデプロイする際は軽くラップするだけで済むってところです。
いちいちサーバ上やローカルにAzure Functionとして配置して動作確認しなくても良いのです。

さらに良かった点はMicrosoft.Extensions.Logging.ILoggerの使い回し。
Azure Functionのエントリーポイントで渡されるILoggerをMicroBatchFrameworkに設定しなおせばデフォルトではコンソールに出力していた情報もApplication Insights等に出力させることができます。
具体的には以下な感じ

ILoggerProviderを継承したクラスを実装
    public class MyLoggerProvider : ILoggerProvider
    {
        private ILogger Logger { get; }
        public MyLoggerProvider(ILogger _logger) => Logger = _logger;
        public ILogger CreateLogger(string categoryName) => Logger;
        public void Dispose() { }
    }
MyLoggerProviderを生成してコンソールアプリケーションに渡す
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            await Program.MainFunction(new[] { (string)req.Query["exec"] }, new MyLoggerProvider(log));

            return (ActionResult)new OkObjectResult("OK");
        }
    }
コンソールアプリのエントリーポイントとは別に入り口を用意
        public static async Task MainFunction(string[] args, ILoggerProvider _loggerProvider)
        {
            await Host.CreateDefaultBuilder()
                .ConfigureLogging((ILoggingBuilder l) => { l.ClearProviders(); l.AddProvider(_loggerProvider); })
                .RunConsoleAppFrameworkAsync(args);
        }

ConfigureLoggingにて(既存のプロバイダを削除して)MyLoggerProviderを追加してあげればAzure Functionで指定しているログ場所へ出力されるようになります。
これでコンソールアプリの時では発生しないAzure Function固有の問題の調査も容易になる思います。

#ConsoleAppFrameworkを採用することで良くなると思うところ

##コンソールアプリ(バッチスクリプト)を使い捨てにしなくて良くなる
業務系だと

  • 黒魔術で書かれたスクリプト
  • ソースがなく挙動がブラックボックスなコンソールアプリ

みたいなのがちらほらあって、いざサーバをリプレースするぞって時に困るんですよね。(動作確認とか作り直しとか)
ConsoleAppFrameworkを採用してコンテナ化して運用すれば環境にもよらなくなるしソースもあるしひとつのアプリで済むので管理が楽になると思います。

CUI <-> GUI の垣根がなくなる

例えばGUIで実装していた機能(ユースケース)をCUIとして提供したいというときに

  • GUIでもフレームワーク採用(Prismとか)
  • DDD
  • SOLID
  • オニオンアーキテクチャ(クリーンアーキテクチャ)

を意識してちゃんと機能(ユースケース)単位で注入できるように設計していたならばConsoleAppFrameworkに乗せ換えることは容易だと思うんですよね。
逆も然りなんですけど。
簡単なバッチ処理でもちゃんとユビキタス言語を用い業務知識として蓄えておけば、いざというとき二度手間をしなくても良くなる気がします。

#まとめ
CUI側にもフレームワークを導入することでGUIと機能の共通化が行えるのはとても魅力的です。
今後はConsoleAppFramework固有の機能についても紹介できればと思います。

21
19
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
21
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?