何时使用
适用:在 Azure 上构建生产级 Functions 无服务器应用,包括 .NET 隔离工作进程模型、Node.js v4 与 Python v2 编程模型、HTTP/队列/定时/Blob 触发器、Durable Functions 编排(函数链 / 扇出扇入 / 长任务异步模式),以及冷启动优化、host.json/扩展包配置与上线前的锋利边缘规避。
不该用(负边界):
- AWS(改用 aws-serverless-builder:Lambda/SAM/CDK)、GCP(改用 gcp-cloud-run:Cloud Run / Cloud Functions)。
- 容器化或长驻后端、非事件触发的常规服务。
- 数据建模(Azure SQL / Cosmos DB)、认证(Azure AD / Easy Auth / 托管标识)、复杂业务编排(Logic Apps / Power Automate)——委派给对应专项技能。
- 不替代针对具体环境的验证、测试与专家评审;缺输入/权限/成功标准时先停下澄清。
核心原则:.NET 新项目一律用隔离工作进程(in-process 2026-11-10 停止支持);客户端用 DI/静态单例复用、绝不在请求内 new HttpClient;全程 async/await,禁止 .Result/.Wait()/Thread.Sleep;连接串/密钥走 App Settings 或 Key Vault;长任务用 Durable Functions 或队列异步而非死等 HTTP。
步骤
- 选编程模型:.NET 用隔离工作进程(
Program.cs+HostBuilder+[Function]);Node.js 用 v4(app.http(...)代码注册、无 function.json);Python 用 v2(@app.route装饰器、强制 Linux 托管、始终隔离进程)。 - 写触发器函数:构造注入
ILogger<T>与服务;统一 try/catch;HTTP 用HttpRequestData/HttpResponseData。 - 装扩展:优先 host.json 扩展包(extensionBundle
[4.*, 5.0.0));隔离工作进程需显式 NuGetMicrosoft.Azure.Functions.Worker.Extensions.*,否则触发器静默不工作。 - 长任务用 Durable Functions:函数链(顺序+自动重试+状态持久化)、扇出扇入(
Task.WhenAll);HTTP 起任务后CreateCheckStatusResponse立即返回状态轮询 URL。 - 队列处理:
[QueueTrigger]失败抛异常触发重试(默认 maxDequeueCount=5)后进毒消息队列<queue>-poison;可加 poison 队列函数告警。 - 优化冷启动:缩包 → 升 Premium 预热实例 + WarmupTrigger 预初始化重资源 → DI 静态单例 → 从包部署(zip)。
- 本地开发:
func host start --verbose确认「Found the following functions」;过校验清单(见注意事项)再部署。
指令
# 创建隔离工作进程 .NET 项目
func init MyFunctionApp --worker-runtime dotnet-isolated
dotnet new func --name MyFunctionApp --framework net8.0
# 本地运行(--verbose 看是否识别到函数)
func host start --verbose
# 从包部署(可降冷启动)
az functionapp deployment source config-zip \
--resource-group myRg --name myFunctionApp \
--src myapp.zip --build-remote true
# Premium 预热/常驻实例(消除扩容冷启动)
az functionapp config set --name <app> --resource-group <rg> \
--prewarmed-instance-count 3
az functionapp config set --name <app> --resource-group <rg> \
--minimum-elastic-instance-count 2
示例
.NET 隔离工作进程 HTTP 触发(DI + 统一错误处理):
// Program.cs
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(services =>
{
services.AddApplicationInsightsTelemetryWorkerService();
services.ConfigureFunctionsApplicationInsights();
services.AddHttpClient(); // 防 socket 耗尽
services.AddSingleton<IMyService, MyService>();
})
.Build();
host.Run();
// HttpTriggerFunction.cs
public class HttpTriggerFunction(ILogger<HttpTriggerFunction> logger, IMyService service)
{
[Function("HttpTrigger")]
public async Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
{
try {
var result = await service.ProcessAsync(req);
var resp = req.CreateResponse(HttpStatusCode.OK);
await resp.WriteAsJsonAsync(result);
return resp;
} catch (Exception ex) {
logger.LogError(ex, "Error processing request");
var resp = req.CreateResponse(HttpStatusCode.InternalServerError);
await resp.WriteAsJsonAsync(new { error = "Internal server error" });
return resp;
}
}
}
Node.js v4(代码注册触发器,无 function.json):
import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
export async function httpTrigger(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
const name = request.query.get("name") || (await request.text()) || "world";
return { status: 200, jsonBody: { message: `Hello, ${name}!` } };
}
app.http("httpTrigger", { methods: ["GET", "POST"], authLevel: "function", handler: httpTrigger });
app.timer("timerTrigger", { schedule: "0 */5 * * * *", handler: async (_t, c) => c.log("tick") });
Python v2(装饰器,强制 Linux 托管):
import azure.functions as func
app = func.FunctionApp(http_auth_level=func.AuthLevel.FUNCTION)
@app.route(route="hello", methods=["GET", "POST"])
async def http_trigger(req: func.HttpRequest) -> func.HttpResponse:
name = req.params.get("name") or "World"
return func.HttpResponse(json.dumps({"message": f"Hello, {name}!"}), mimetype="application/json")
@app.queue_trigger(arg_name="msg", queue_name="myqueue", connection="AzureWebJobsStorage")
def queue_trigger(msg: func.QueueMessage) -> None:
logging.info(msg.get_body().decode("utf-8"))
Durable Functions——函数链 + 长任务异步:编排函数 [OrchestrationTrigger] TaskOrchestrationContext 内顺序 await context.CallActivityAsync(...),状态自动持久化、瞬时失败自动重试、可跨进程重启存活;HTTP 起始函数注入 [DurableClient] DurableTaskClient,ScheduleNewOrchestrationInstanceAsync 后 return client.CreateCheckStatusResponse(req, instanceId) 立即返回,客户端轮询 statusQueryGetUri。扇出扇入:var tasks = items.Select(i => context.CallActivityAsync<R>("Act", i)); var results = await Task.WhenAll(tasks);。
队列触发毒消息(host.json 队列配置):
{ "version": "2.0", "extensions": { "queues": {
"visibilityTimeout": "00:00:30", "batchSize": 16, "maxDequeueCount": 5 } } }
注意事项
锋利边缘(高危):
- HTTP 硬性 230 秒超时(与计划无关):Azure 负载均衡器固定 230s 空闲超时,host.json 的 functionTimeout 对 HTTP 无效,超时报 504 但函数仍在跑。长任务改用 Durable Functions 异步模式 / 队列异步 / Webhook 回调。
- HttpClient 实例化致 socket 耗尽:每请求 new HttpClient 会留 TIME_WAIT(约 240s)耗尽端口,本地正常生产崩。用
IHttpClientFactory(services.AddHttpClient<T>)或静态客户端;CosmosClient/BlobServiceClient/ServiceBusClient 同理用 DI/静态。 - 阻塞 async 致线程饥饿:
.Result/.Wait()/Thread.Sleep占住线程,高并发死锁。全程await+await Task.Delay(...);只在入口MainAsync().GetAwaiter().GetResult()。 - in-process 模型 2026-11-10 停止支持:新项目用隔离工作进程;迁移要点:
FunctionName→Function、HttpRequest→HttpRequestData、IActionResult→HttpResponseData、ILogger改构造注入、补Program.cs。
中危:
- 消费计划硬上限 10 分钟(默认 5):超时悄无声息截断。host.json 配
functionTimeout: 00:10:00(消费计划上限),更长用 Premium(默认 30 分钟,可去除即无界)、Durable Functions 或队列分块。 - 隔离工作进程注入的
ILogger<T>不输出日志:本地/App Insights 可能丢日志。Program.cs配AddApplicationInsightsTelemetryWorkerService()+ConfigureFunctionsApplicationInsights();可靠起见用context.GetLogger<T>();本地查 local.settings.json 的APPLICATIONINSIGHTS_CONNECTION_STRING。 - 缺扩展包致静默失败:「No job functions found」、绑定不生效。检查 host.json extensionBundle 或隔离工作进程的显式 NuGet
...Worker.Extensions.*,func host start --verbose确认识别。 - Premium 计划仍有冷启动:预热实例默认仅 1 个、快速扩容仍冷、且预热的是运行时不是你的代码。加 WarmupTrigger 预初始化、提高
--prewarmed-instance-count、用Lazy<T>/连接池、必要时--minimum-elastic-instance-count(常驻、最贵)。
校验清单(部署前自检):
- ERROR:禁止硬编码连接串 / API Key(用 Key Vault 或 App Settings);禁止
.Result/.Wait()/Thread.Sleep(用 await / Task.Delay)。 - WARNING:避免每请求 new HttpClient 或
using包裹 HttpClient(用 IHttpClientFactory/静态);隔离工作进程的 HttpTrigger 必须带[Function]属性;生产 Anonymous 授权级别需 APIM/其他鉴权兜底。 - INFO:仍用 in-process
FunctionName属性应考虑迁移隔离工作进程。
互见
- AWS 无服务器 → aws-serverless-builder(Lambda、API Gateway、SAM/CDK)
- GCP 无服务器 → gcp-cloud-run(容器用 Cloud Run、事件用 Cloud Functions)
- Azure 架构 → azure-cloud-architect(订阅/资源组/网络与整体云架构)
- 基础设施即代码 → terraform-specialist(用 Terraform 管理 Function App 资源)
采编自 sickn33/antigravity-awesome-skills(MIT)。原 skill 标注上游来源为 vibeship-spawner-skills(Apache 2.0)。