用 Swift 编写 Azure Functions。
免责声明:这是一个社区开源项目,而非官方的 Azure 项目。
将示例项目部署到 Azure!
经典工作进程示例
自定义处理程序示例
一个定时器函数(自定义处理程序)
import Foundation
import AzureFunctions
import Vapor
class TimerFunction: Function {
required init() {
super.init()
self.name = "TimerFunction"
self.functionJsonBindings =
[
[
"type" : "timerTrigger",
"name" : "myTimer",
"direction" : "in",
"schedule" : "*/5 * * * * *"
]
]
//or
//self.trigger = TimerTrigger(name: "myTimer", schedule: "*/5 * * * * *")
app.post([PathComponent(stringLiteral: name)], use: run(req:))
}
func run(req: Request) -> InvocationResponse {
var res = InvocationResponse()
res.appendLog("Its is time!")
return res
}
}
一个 HTTP 函数(经典工作进程)
import Foundation
import AzureFunctions
class HttpFunction: Function {
required init() {
super.init()
self.name = "HttpFunction"
self.trigger = HttpRequest(name: "req")
}
override func exec(request: HttpRequest, context: inout Context, callback: @escaping callback) throws {
let res = HttpResponse()
var name: String?
if let data = request.body, let bodyObj: [String: Any] = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
name = bodyObj["name"] as? String
} else {
name = request.query["name"]
}
res.body = "Hello \(name ?? "buddy")!".data(using: .utf8)
return callback(res);
}
}
Swift 安装:https://swiftlang.cn/getting-started/#installing-swift
安装最新的 Azure Functions Core Tools。
与 Core Tools 类似,Swift Functions Tools 使 Swift 函数的开发更加容易和方便。
在 macOS 上,您可以从 Homebrew 🍺 安装它
brew install salehalbuga/formulae/swift-func
在 Linux 上,
克隆工具仓库
git clone https://github.com/SalehAlbuga/azure-functions-swift-tools
安装
make install
它安装一个名为 swiftfunc
的 CLI 工具,该工具可用于创建项目、函数并在本地运行它们。
运行 init 命令以创建一个新的 Azure Functions 应用程序
swiftfunc init myApp [-hw]
它将在一个新文件夹中创建一个新应用程序,并在 Sources 目标内的名为 functions
的文件夹中创建函数应该放置的位置 (/myApp/Sources/myApp/functions)。 创建的项目是一个带有 Azure Functions 框架依赖项的 Swift 包项目。
传递 -hw
或 --http-worker
选项以使用 自定义处理程序 模板创建项目。
在项目的新目录中,运行以下命令以创建一个名为 hello
的新 HTTP 函数
swiftfunc new http -n hello [-hw]
新的函数文件将在以下路径中创建 Sources/myApp/functions/hello.swift
。
与 init
命令类似,传递 -hw
或 --http-worker
选项以使用自定义处理程序模板创建新函数。
在项目目录中运行 swiftfunc run
以在本地运行您的 Swift Functions 项目。 它将编译代码并为您启动主机 * (就好像您在运行 func host start
)*。 主机输出应该显示您上面创建的 hello
函数的 URL。 单击它以运行该函数并查看输出!
有两种方法可以将 Swift Functions 部署到 Azure
要将 Function 应用程序部署到容器中,您可以选择使用 Functions Core Tool func deploy
命令,它将构建镜像、将其推送到注册表并在目标 Function App 中设置它,或者您可以手动执行此操作,如下所示。
构建镜像 (创建项目时提供 Dockerfile)
docker build -t <imageTag> .
如果您使用 DockerHub,则标签将为 username/imageName:version
。 如果您使用 ACR (Azure Container Registry) 或任何其他私有注册表,则标签将为 registryURL/imageName:version
然后推送它
docker push <imageTag>
在 Azure 门户 中,创建一个新的 Function App,并将 **Docker Container** 作为发布选项。 在 Hosting options 下,确保选择 Linux 作为操作系统。
创建应用程序后或在任何现有的容器函数应用程序中,在 Platform Features 下,选择 Container settings 并设置注册表并选择您推送的镜像。
您可以使用下面的按钮将预构建的示例项目部署到您的 Azure 订阅
自定义处理程序示例
首先,您需要在 Azure 的 Function App 中设置以下应用程序设置。LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/site/wwwroot/workers/swift/lib/
然后取决于您是在 Linux 机器还是 Mac 上进行开发
从 Azure CLI 登录到您的 Azure 帐户
az login
当 Azure CLI 完成加载您的订阅信息后,运行
swiftfunc publish myswiftfunctions
Swift Function Tools 发布命令将编译、导出和发布您的 Swift Functions 项目。
从 macOS 发布到 Linux 消耗计划中的 Function App 需要首先在 Linux 容器中构建该应用程序,为此,您可以使用 VSCode Dev Containers。 需要使用 -dc
或 --dev-container
选项创建项目,以便添加 Swift Function Dev Container(或者您可以创建一个新的容器并将 .devcontainer 文件夹复制到您的项目)。 swiftfunc init myFunctionApp -hw -dc
在开发容器中重新打开文件夹 (Command-Shift-P,搜索并选择 *Remote-Containers: Reopen in Container*)
一旦开发容器准备就绪,请按照上述相同的 Linux 步骤发布应用程序!
Azure Functions 提供了各种 绑定和触发器
函数的触发器、输入绑定和输出绑定在其初始化程序中设置。 Swift 中的 Azure Functions 必须继承框架中的 Function 类。
当使用自定义处理程序模式时,您可以通过将 functionJsonBindings
属性设置为 Azure Functions docs 中绑定/触发器的 JSON 配置,来使用所有 Azure Functions 绑定和触发器。 您还可以使用下面列出的框架支持的触发器/绑定类型。
目前此模式支持以下内容。 未来将实现更多的绑定,并进行许多改进。
Swift 类型 | Azure Functions 绑定 | 方向 |
---|---|---|
HttpRequest | HTTP 触发器 | 输入 |
HttpResponse | 输出 HTTP 响应 | 输出 |
TimerTrigger | 定时器触发器 | 输入 |
消息数据类型 String (构造函数中定义的 Table 绑定) | 输入和输出表 | 输入,输出 |
消息数据类型 String (构造函数中定义的 Queue 绑定) | 输出队列消息 | 输出 |
消息数据类型 String (构造函数中定义的 Queue 绑定) | 队列触发器 | 输入 |
Blob (blob 数据 prob 是 String 或 Data) | 输入 Blob | 输入 |
String 或 Data | 输出 Blob | 输出 |
Blob | Blob 触发器 | 输入 |
ServiceBusMessage | Service Bus 输出消息 | 输出 |
ServiceBusMessage | Service Bus 触发器 | 输入 |
import AzureFunctions
import Vapor
class QueueFunction: Function {
required init() {
super.init()
self.name = "QueueFunction"
self.functionJsonBindings = [
[
"connection" : "AzureWebJobsStorage",
"type" : "queueTrigger",
"name" : "myQueueTrigger",
"queueName" : "myqueue",
"direction" : "in"
]
]
// or
//self.trigger = Queue(name: "myQueueTrigger", queueName: "myqueue", connection: "AzureWebJobsStorage")
app.post([PathComponent(stringLiteral: name)], use: run(req:))
}
func run(req: Request) -> InvocationResponse {
...
import AzureFunctions
class HttpFunction: Function {
required init() {
super.init()
self.name = "HttpFunction"
self.trigger = HttpRequest(name: "req")
self.inputBindings = [Blob(name: "fileInput", path: "container/myBlob.json", connection: "AzureWebJobsStorage")]
self.outputBindings = [Queue(name: "queueOutput", queueName: "myQueue", connection: "AzureWebJobsStorage")]
}
override func exec(request: HttpRequest, context: inout Context, callback: @escaping callback) throws {
...
根据您的函数的触发器类型,工作进程将调用适当的 exec
重载。 例如,如果该函数是定时器触发的,则工作进程将调用
exec(timer:context:callback:)
如果它是一个 HTTP 触发的函数
exec(request:context:callback:)
您可以在 Xcode 中查看可用重载的列表。
输入和输出绑定在上下文中可用作字典,您可以在其中使用构造函数中指定的绑定名称访问/设置值。 例如
let tableVal = context.inputBindings["myTableInput"]
context.outputBindings["myQueueOutput"] = "new item!"
该框架使用 Vapor 4.0 HTTP 服务器。 Function
类具有 app
属性,它是您可以用来注册您的函数 HTTP 路由的 Vapor 应用程序实例。
class myFunction: Function {
required init() {
super.init()
self.name = "myFunction"
self.functionJsonBindings = [
[
"connection" : "AzureWebJobsStorage",
"type" : "queueTrigger",
"name" : "myQueueTrigger",
"queueName" : "myqueue",
"direction" : "in"
]
]
app.post([PathComponent(stringLiteral: name)], use: run(req:))
}
func run(req: Request) -> InvocationResponse {
var res = InvocationResponse()
if let payload = try? req.content.decode(InvocationRequest.self) {
res.appendLog("Got \\(payload.Data?["myQueueTrigger"] ?? "")")
}
return res
}
}
该框架还提供了 Azure Function 主机所需的函数调用 Request 和 Response 模型,它们符合 Vapor 的 Content 协议,以及辅助方法。
调用请求
/// Trigger/Bindings data (values).
var data: [String:AnyCodable]?
/// Trigger/Bindings metadata.
var metadata: [String:AnyCodable]?
调用请求
/// Output bindings values dictionary
var outputs: [String:AnyCodable]?
/// Functions logs array. These will be logged when the Function is executed
var logs: [String] = []
/// The $return binding value
var returnValue: AnyCodable?
由于框架正在积极更新,如果您遇到任何问题或想要获得最新的功能和改进,请更新框架和工具。
更新框架
swift package update
在 macOS 上更新工具
brew upgrade salehalbuga/formulae/swift-func
在 Linux 上
git clone https://github.com/SalehAlbuga/azure-functions-swift-tools
make install
在生成的 main.swift
中,您可以定义您的调试 AzureWebJobsStorage
,并可选择定义任何其他连接/环境变量。 此外,您可以更改默认的 Extension Bundle id 和版本。
//
// main.swift
//
//
// Auto Generated by SwiftFunctionsSDK
//
// Only set env vars or register/remove Functions. Do Not modify/add other code
//
import AzureFunctions
let registry = FunctionRegistry()
registry.AzureWebJobsStorage = "yourConnection" //Remove before deploying. Do not commit or push any Storage Account keys
registry.EnvironmentVariables = ["queueStorageConnection": "otherConnection"]
// Optionally you can change the default ExtensionBundleId and version
registry.ExtensionBundleId = "Microsoft.Azure.Functions.ExtensionBundle"
registry.ExtensionBundleVersion = "[1.*, 2.0.0)"
registry.register(hello.self)
...
请确保不要将任何调试存储帐户密钥提交到存储库
传统工作进程(经典)
您可以使用 context
对象中的 log 方法进行记录
context.log(_)
自定义处理程序 (HTTP Worker)
日志在 InvocationResponse 对象中返回。 您可以附加日志
res.appendLog(_)
传统工作进程(经典)
当您的函数完成执行逻辑时,您应该调用提供的回调,传递 $return
输出绑定值,如果没有,则传递 true
。
callback(res)