Azure functions でexeを使う


やりたいこと

Blob Storageに配置されたオブジェクトをexeで処理したい

前提

  • Blob Triggerなど Blogとバインディングされたfunctionを登録
  • functionの場所にBinフォルダを用意
  • exeをBinフォルダに置いておく

やりかた

例) ffmpegで動画ファイルから音声だけ抜き出す

function.json
{
  "bindings": [
    {
      "name": "myBlob",
      "type": "blobTrigger",
      "direction": "in",
      "path": "files/{name}",
      "connection": "xxx_STORAGE"
    },
    {
      "type": "blob",
      "name": "outputBlob",
      "path": "files/{rand-guid}.wav",
      "connection": "xxx_STORAGE",
      "direction": "out"
    }
  ],
  "disabled": false
}

以下、ソース内コメントで解説

run.csx
#r "Microsoft.WindowsAzure.Storage"

using Microsoft.WindowsAzure.Storage.Blob;
using System;
using System.Diagnostics;

public static void Run(CloudBlockBlob myBlob, string name, string blobTrigger, Stream outputBlob, TraceWriter log)
{
    try {
        // フルパス
        String basePath = @"D:\home\site\wwwroot\BlobTriggerCSharp\";
        String stFilePath = basePath + name;

        // ファイルをダウンロード
        myBlob.DownloadToFile(stFilePath, System.IO.FileMode.Create);

        System.Diagnostics.Process process = new System.Diagnostics.Process();
        System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();

        // exeを指定
        startInfo.FileName = basePath + @"Bin\ffmpeg.exe";

        // 実行時パラメータを指定
        startInfo.Arguments = "-i " + stFilePath + " -ac 1 -ar 16000 -acodec pcm_s16le -f wav " + basePath + "sample.wav";

        // ウインドウ非表示
        startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;

        // 標準エラー出力をリダイレクト
        startInfo.RedirectStandardError = true;

        // 標準出力をリダイレクト
        startInfo.RedirectStandardOutput = true;

        // シェル実行ではない
        startInfo.UseShellExecute = false;
        process.StartInfo = startInfo;

        // 実行
        process.Start();

        // 処理完了をまつ
        process.WaitForExit();

        // 出力したファイルを読み込む
        FileStream SourceStream = File.Open(basePath + "sample.wav", FileMode.Open);

        // 出力用blobに出力
        SourceStream.CopyTo(outputBlob);        

        // 標準エラー出力をログ出力
        StreamReader myStreamReader = process.StandardError;
        log.Info( myStreamReader.ReadLine());

        // 標準出力をログ出力
        StreamReader myStreamReader2 = process.StandardOutput;
        log.Info( myStreamReader2.ReadLine());

        // 読み取り専用を解除
        System.IO.FileInfo cFileInfo = new System.IO.FileInfo(stFilePath);
        if ((cFileInfo.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly){
            cFileInfo.Attributes = FileAttributes.Normal;
        }
        // 使い終わったファイルを削除
        cFileInfo.Delete();

    } catch(Exception e) {
        log.Info(e.Message);
        log.Info(e.StackTrace);
    }
}


注意

上記例だと、トリガーを設定している入力用blobと出力用blobが同じなので、ファイルができた瞬間に再度呼ばれてしまう。
エラーになるので無限ループにはならない。

azure functions も C# script も初めて使ったので、書き方おかしかったりしたらご指摘ください。

参考

Azure Functions で EXEを実行する