Azure Functions是Azure的Serverless服務,非常適合用來處理需要快速開發佈署、任務單純的需求;使用Azure Functions的Dynamic層級時,系統會依照資源使用量自動調整系統規模,減少管理的人力與時間。
在為北京的客戶建立物聯網方案時,我們使用Azure Functions來作為呼叫第三方服務的方式;傳統設備端的數據進到IoT Hub之後,利用Stream Analytics挑出事件並放到Service Bus Queue中,然後利用Azure Functions把數據透過REST API傳給第三方服務。由於Queue的特性,我們可以簡單地達到保證送達;並且因為任務單純明確,使用Azure Functions可以很快的完成需求。
方案架構大約如下
<![if !supportLists]>1. <![endif]>建立完Azure Functions後,在管理介面建立一個以C#撰寫的Http Trigger Azure Functions
<![if !supportLists]>2. <![endif]>在這裡指定Service Bus Queue的相關資訊;由於Azure Functions底層是Web Jobs,這些連線資訊最後會被寫到Web App的Application Settings裡。
<![if !supportLists]> i. <![endif]>如果服務需要額外的輸入;例如,從Service Bus Queue取得訊息之後,還必須根據他的Message Id到Document DB把相對應的文件取出來在程式中比對,可以在這裡增加額外的輸入。
<![if !supportLists]> ii. <![endif]>以documentDB為例,假如我們的Service Bus Queue message會有一個欄位叫做documentId,那麼可以在以下Document ID的位置中輸入{documentId}告訴Azure Functions,要在指定的DocumentDB中把documentId欄位值為Service Bus Queue訊息中documentId屬性值相同的文件抓出來,做為另一個輸入。
<![if !supportLists]>3. <![endif]>在這個例子中,我們沒有額外的輸入,也不需要輸出(回應訊息);因此直接案下完成建立即可
<![if !supportLists]>4. <![endif]>接著回到開發頁簽,就可以在編輯器中寫程式了
<![if !supportLists]> i. <![endif]>因為是C#,系統預先Reference了一些預設的Assembly,詳情可以參考這裡:https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-csharp
<![if !supportLists]> ii. <![endif]>底層是Windows Server,.Net Framework裡的Assembly可以透過#r的方式reference,例如
#r "Newtonsoft.Json"
<![if !supportLists]> iii. <![endif]>如果需要額外的NuGet Package,可以加入一個名為Project.json的檔案,透過Json方式定義所需的Package
<![if !supportLists]>5. <![endif]>回到我們的範例,我的目的是把訊息從Service Bus Queue讀出來後,呼叫REST API;代碼非常簡單;完整的程式範例在:https://github.com/michael-chi/YFIOPOC/tree/master/Functions/QueueToYFIOAPI
public static void Run(string myQueueItem, TraceWriter log)
{
log.Info($"C# ServiceBus queue trigger function processed message: {myQueueItem}");
ChangedData data = JsonConvert.DeserializeObject<ChangedData>(myQueueItem);
var logText = JsonConvert.SerializeObject(data);
log.Info($"Message sending to YFIOAPO:{logText}");
log.Info("Calling YFIO API...");
var resp = YFIOHelper.Instance(data.ProjectId).WriteIOValues(data.Names,data.Values);
log.Info($"Done...[RESP:{resp}]");
}
<![if !supportLists]>6. <![endif]>完成後,在管理介面啟用即可