From a7b077831fe755e6b26b05d332ca3f458c5464c7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:56:46 +0000 Subject: [PATCH 1/3] Initial plan From b2e8b4abea5153c8638b5dec5cd1c9ae2ac0aeb0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Sep 2025 15:08:16 +0000 Subject: [PATCH 2/3] Add Azure Container App Jobs documentation and ASPIREAZURE002 diagnostic Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com> --- docs/azure/container-app-jobs.md | 190 ++++++++++++++++++ .../AspireContainerAppJobs.AppHost.sln | 18 ++ .../AspireContainerAppJobs.AppHost.csproj | 17 ++ .../AspireContainerAppJobs.AppHost/Program.cs | 33 +++ docs/diagnostics/aspireazure002.md | 53 +++++ docs/diagnostics/overview.md | 1 + docs/toc.yml | 3 + 7 files changed, 315 insertions(+) create mode 100644 docs/azure/container-app-jobs.md create mode 100644 docs/azure/snippets/container-app-jobs/AspireContainerAppJobs.AppHost/AspireContainerAppJobs.AppHost.sln create mode 100644 docs/azure/snippets/container-app-jobs/AspireContainerAppJobs.AppHost/AspireContainerAppJobs.AppHost/AspireContainerAppJobs.AppHost.csproj create mode 100644 docs/azure/snippets/container-app-jobs/AspireContainerAppJobs.AppHost/AspireContainerAppJobs.AppHost/Program.cs create mode 100644 docs/diagnostics/aspireazure002.md diff --git a/docs/azure/container-app-jobs.md b/docs/azure/container-app-jobs.md new file mode 100644 index 0000000000..b7fbb7d9d5 --- /dev/null +++ b/docs/azure/container-app-jobs.md @@ -0,0 +1,190 @@ +--- +title: Azure Container App Jobs +description: Learn how to use Azure Container App Jobs in .NET Aspire to run containerized tasks that execute for a finite duration. +ms.date: 09/16/2025 +ms.topic: how-to +--- + +# Azure Container App Jobs + +Azure Container Apps jobs enable you to run containerized tasks that execute for a finite duration and exit. You can use jobs to perform tasks such as data processing, machine learning, or any scenario where on-demand processing is required. Unlike traditional Azure Container Apps that run continuously, Container App Jobs are designed for batch processing, scheduled tasks, and event-driven workloads. + +.NET Aspire provides support for Azure Container App Jobs through the `PublishAsAzureContainerAppJob` extension method, allowing you to deploy your .NET projects, containers, and executables as jobs in Azure Container Apps. + +## Prerequisites + +- Azure subscription +- .NET Aspire project +- Understanding of [Azure Container Apps Jobs](/azure/container-apps/jobs) + +## Supported resource types + +.NET Aspire allows you to publish the following resource types as Azure Container App Jobs: + +- : Represents a specified container. +- : Represents a specified executable process. +- : Represents a specified .NET project. + +## Publishing as Azure Container App Jobs + +To publish resources as Azure Container App Jobs, use the following APIs: + +- +- +- + +## Basic usage + +The following example demonstrates how to configure a .NET project as an Azure Container App Job with a scheduled trigger: + +```csharp +var builder = DistributedApplication.CreateBuilder(); + +builder.AddProject("data-processor") + .PublishAsAzureContainerAppJob((_, job) => + { + job.Configuration.TriggerType = ContainerAppJobTriggerType.Schedule; + job.Configuration.ScheduleTriggerConfig.CronExpression = "0 0 * * *"; // Every day at midnight + }); +``` + +This code: + +- Creates a new distributed application builder. +- Adds a project named `data-processor` to the builder. +- Calls `PublishAsAzureContainerAppJob` to configure the project as a Container App Job. +- Sets the trigger type to `Schedule` with a cron expression to run daily at midnight. + +## Job trigger types + +Azure Container App Jobs support different trigger types: + +### Manual trigger + +Use manual triggers for on-demand job execution: + +```csharp +builder.AddProject("manual-task") + .PublishAsAzureContainerAppJob((_, job) => + { + job.Configuration.TriggerType = ContainerAppJobTriggerType.Manual; + }); +``` + +### Schedule trigger + +Use schedule triggers for time-based job execution: + +```csharp +builder.AddProject("scheduled-task") + .PublishAsAzureContainerAppJob((_, job) => + { + job.Configuration.TriggerType = ContainerAppJobTriggerType.Schedule; + job.Configuration.ScheduleTriggerConfig.CronExpression = "0 */6 * * *"; // Every 6 hours + job.Configuration.ScheduleTriggerConfig.Parallelism = 1; + job.Configuration.ScheduleTriggerConfig.CompletionCount = 1; + }); +``` + +### Event trigger + +Use event triggers for reactive job execution based on external events: + +```csharp +builder.AddProject("event-task") + .PublishAsAzureContainerAppJob((_, job) => + { + job.Configuration.TriggerType = ContainerAppJobTriggerType.Event; + job.Configuration.EventTriggerConfig.Scale.MinReplicas = 0; + job.Configuration.EventTriggerConfig.Scale.MaxReplicas = 10; + job.Configuration.EventTriggerConfig.Parallelism = 1; + job.Configuration.EventTriggerConfig.CompletionCount = 1; + }); +``` + +## Advanced configuration + +### Setting resource requirements + +Configure CPU and memory resources for your job: + +```csharp +builder.AddProject("intensive-task") + .PublishAsAzureContainerAppJob((_, job) => + { + job.Configuration.TriggerType = ContainerAppJobTriggerType.Manual; + job.Template.InitContainers[0].Resources.Cpu = "1.0"; + job.Template.InitContainers[0].Resources.Memory = "2Gi"; + }); +``` + +### Environment variables + +Add environment variables to your job: + +```csharp +var connectionString = builder.AddParameter("connectionString"); + +builder.AddProject("db-task") + .PublishAsAzureContainerAppJob((infra, job) => + { + job.Configuration.TriggerType = ContainerAppJobTriggerType.Manual; + job.Template.InitContainers[0].Env.Add(new ContainerAppEnvironmentVariable + { + Name = "ConnectionString", + Value = connectionString.AsProvisioningParameter(infra) + }); + }); +``` + +### Timeout and retry policy + +Configure job execution timeout and retry behavior: + +```csharp +builder.AddProject("retryable-task") + .PublishAsAzureContainerAppJob((_, job) => + { + job.Configuration.TriggerType = ContainerAppJobTriggerType.Manual; + job.Configuration.TimeoutInSeconds = 1800; // 30 minutes + job.Configuration.RetryPolicy.RetryLimit = 3; + job.Configuration.RetryPolicy.RetryLimitPolicy = ContainerAppJobRetryLimitPolicy.RestartFailedContainers; + }); +``` + +## Container resources + +You can also publish container resources as Azure Container App Jobs: + +```csharp +builder.AddContainer("batch-processor", "myregistry.azurecr.io/batch-processor:latest") + .PublishAsAzureContainerAppJob((_, job) => + { + job.Configuration.TriggerType = ContainerAppJobTriggerType.Schedule; + job.Configuration.ScheduleTriggerConfig.CronExpression = "0 2 * * 0"; // Weekly on Sunday at 2 AM + }); +``` + +## Executable resources + +Executable resources can also be published as jobs: + +```csharp +builder.AddExecutable("data-script", "python", ".", "process_data.py") + .PublishAsAzureContainerAppJob((_, job) => + { + job.Configuration.TriggerType = ContainerAppJobTriggerType.Manual; + }); +``` + +## Experimental feature notice + +> [!IMPORTANT] +> Azure Container App Jobs support in .NET Aspire is an experimental feature. The APIs are subject to change in future releases. You might encounter the diagnostic `ASPIREAZURE002` when using these features. For more information, see [ASPIREAZURE002](../diagnostics/aspireazure002.md). + +## Related content + +- [Configure Azure Container Apps environments](configure-aca-environments.md) +- [Azure Container Apps Jobs documentation](/azure/container-apps/jobs) +- [Deploy a .NET Aspire project to Azure Container Apps](../deployment/azure/aca-deployment.md) +- [Customize Azure resources](customize-azure-resources.md) diff --git a/docs/azure/snippets/container-app-jobs/AspireContainerAppJobs.AppHost/AspireContainerAppJobs.AppHost.sln b/docs/azure/snippets/container-app-jobs/AspireContainerAppJobs.AppHost/AspireContainerAppJobs.AppHost.sln new file mode 100644 index 0000000000..5a0ba64b0e --- /dev/null +++ b/docs/azure/snippets/container-app-jobs/AspireContainerAppJobs.AppHost/AspireContainerAppJobs.AppHost.sln @@ -0,0 +1,18 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspireContainerAppJobs.AppHost", "AspireContainerAppJobs.AppHost\AspireContainerAppJobs.AppHost.csproj", "{8A7E0E97-E29E-42C9-9A52-4B27D3C8F95B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8A7E0E97-E29E-42C9-9A52-4B27D3C8F95B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A7E0E97-E29E-42C9-9A52-4B27D3C8F95B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A7E0E97-E29E-42C9-9A52-4B27D3C8F95B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A7E0E97-E29E-42C9-9A52-4B27D3C8F95B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal \ No newline at end of file diff --git a/docs/azure/snippets/container-app-jobs/AspireContainerAppJobs.AppHost/AspireContainerAppJobs.AppHost/AspireContainerAppJobs.AppHost.csproj b/docs/azure/snippets/container-app-jobs/AspireContainerAppJobs.AppHost/AspireContainerAppJobs.AppHost/AspireContainerAppJobs.AppHost.csproj new file mode 100644 index 0000000000..5daad09608 --- /dev/null +++ b/docs/azure/snippets/container-app-jobs/AspireContainerAppJobs.AppHost/AspireContainerAppJobs.AppHost/AspireContainerAppJobs.AppHost.csproj @@ -0,0 +1,17 @@ + + + + Exe + net9.0 + enable + enable + true + d50c4adc-e07e-4b2a-b03e-b8c47c4e50b2 + + + + + + + + \ No newline at end of file diff --git a/docs/azure/snippets/container-app-jobs/AspireContainerAppJobs.AppHost/AspireContainerAppJobs.AppHost/Program.cs b/docs/azure/snippets/container-app-jobs/AspireContainerAppJobs.AppHost/AspireContainerAppJobs.AppHost/Program.cs new file mode 100644 index 0000000000..afdeebb474 --- /dev/null +++ b/docs/azure/snippets/container-app-jobs/AspireContainerAppJobs.AppHost/AspireContainerAppJobs.AppHost/Program.cs @@ -0,0 +1,33 @@ +var builder = DistributedApplication.CreateBuilder(args); + +// Example: Scheduled data processing job +builder.AddProject("data-processor") + .PublishAsAzureContainerAppJob((_, job) => + { + job.Configuration.TriggerType = ContainerAppJobTriggerType.Schedule; + job.Configuration.ScheduleTriggerConfig.CronExpression = "0 0 * * *"; // Every day at midnight + }); + +// Example: Manual trigger job with environment variables +var connectionString = builder.AddParameter("connectionString"); + +builder.AddProject("db-task") + .PublishAsAzureContainerAppJob((infra, job) => + { + job.Configuration.TriggerType = ContainerAppJobTriggerType.Manual; + job.Template.InitContainers[0].Env.Add(new ContainerAppEnvironmentVariable + { + Name = "ConnectionString", + Value = connectionString.AsProvisioningParameter(infra) + }); + }); + +// Example: Container resource as a job +builder.AddContainer("batch-processor", "myregistry.azurecr.io/batch-processor:latest") + .PublishAsAzureContainerAppJob((_, job) => + { + job.Configuration.TriggerType = ContainerAppJobTriggerType.Schedule; + job.Configuration.ScheduleTriggerConfig.CronExpression = "0 2 * * 0"; // Weekly on Sunday at 2 AM + }); + +builder.Build().Run(); \ No newline at end of file diff --git a/docs/diagnostics/aspireazure002.md b/docs/diagnostics/aspireazure002.md new file mode 100644 index 0000000000..a9df94f59e --- /dev/null +++ b/docs/diagnostics/aspireazure002.md @@ -0,0 +1,53 @@ +--- +title: Compiler Error ASPIREAZURE002 +description: Learn more about compiler Error ASPIREAZURE002. Azure Container App Jobs are for evaluation purposes only and are subject to change or removal in future updates. +ms.date: 09/16/2025 +f1_keywords: + - "ASPIREAZURE002" +helpviewer_keywords: + - "ASPIREAZURE002" +--- + +# Compiler Error ASPIREAZURE002 + +**Version introduced:** 9.5 + +> Azure Container App Jobs are for evaluation purposes only and are subject to change or removal in future updates. Suppress this diagnostic to proceed. + +The .NET Aspire Azure hosting integration now ships with support for Azure Container App Jobs. If you're using any of the `PublishAsAzureContainerAppJob` APIs, you might see a compiler error/warning indicating that the API is experimental. This behavior is expected, as the API is still in preview and the shape of this API is expected to change in the future. + +## Example + +The following code generates `ASPIREAZURE002`: + +```csharp +builder.AddProject("data-processor") + .PublishAsAzureContainerAppJob((_, job) => + { + job.Configuration.TriggerType = ContainerAppJobTriggerType.Schedule; + job.Configuration.ScheduleTriggerConfig.CronExpression = "0 0 * * *"; + }); +``` + +## To correct this Error + +Suppress the Error with either of the following methods: + +- Set the severity of the rule in the _.editorconfig_ file. + + ```ini + [*.{cs,vb}] + dotnet_diagnostic.ASPIREAZURE002.severity = none + ``` + + For more information about editor config files, see [Configuration files for code analysis rules](/dotnet/fundamentals/code-analysis/configuration-files). + +- Add the following `PropertyGroup` to your project file: + + ```xml + + $(NoWarn);ASPIREAZURE002 + + ``` + +- Suppress in code with the `#pragma warning disable ASPIREAZURE002` directive. diff --git a/docs/diagnostics/overview.md b/docs/diagnostics/overview.md index 081041a550..c02496aef1 100644 --- a/docs/diagnostics/overview.md +++ b/docs/diagnostics/overview.md @@ -20,6 +20,7 @@ The following table lists the possible MSBuild and .NET Analyzer warnings and er | [`ASPIRE008`](aspire008.md) | Error | The Aspire workload that this project depends on is now deprecated. | | [`ASPIREACADOMAINS001`](aspireacadomains001.md) | (Experimental) Error | `ConfigureCustomDomain` is for evaluation purposes only and is subject to change or removal in future updates. | | [`ASPIREAZURE001`](aspireazure001.md) | (Experimental) Error | Publishers are for evaluation purposes only and are subject to change or removal in future updates. | +| [`ASPIREAZURE002`](aspireazure002.md) | (Experimental) Error | Azure Container App Jobs are for evaluation purposes only and are subject to change or removal in future updates. | | [`ASPIRECOMPUTE001`](aspirecompute001.md) | (Experimental) Error | Compute related types and members are for evaluation purposes only and is subject to change or removal in future updates. | | [`ASPIRECOSMOSDB001`](aspirecosmosdb001.md) | (Experimental) Error | `RunAsPreviewEmulator` is for evaluation purposes only and is subject to change or removal in future updates. | | [`ASPIREHOSTINGPYTHON001`](aspirehostingpython001.md) | (Experimental) Error | `AddPythonApp` is for evaluation purposes only and is subject to change or removal in future updates. | diff --git a/docs/toc.yml b/docs/toc.yml index 8dd55660fa..fd271858aa 100644 --- a/docs/toc.yml +++ b/docs/toc.yml @@ -220,6 +220,9 @@ items: href: azure/local-provisioning.md - name: Configure Azure Container Apps environments href: azure/configure-aca-environments.md + - name: Azure Container App Jobs + displayName: container app jobs,jobs,batch processing,scheduled tasks + href: azure/container-app-jobs.md - name: User-assigned managed identity href: azure/user-assigned-managed-identity.md - name: Manage role assignments From d8d84d59eb42cd35ec587e1c912b7a4bc36df036 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Sep 2025 15:09:36 +0000 Subject: [PATCH 3/3] Add cross-reference from integrations overview to Container App Jobs Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com> --- docs/azure/integrations-overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/azure/integrations-overview.md b/docs/azure/integrations-overview.md index 29006f09a2..abee29c819 100644 --- a/docs/azure/integrations-overview.md +++ b/docs/azure/integrations-overview.md @@ -325,7 +325,7 @@ The preceding code: - Adds an environment variable named `Hello` to the container app, using the `env` parameter. - The `AsProvisioningParameter` method is used to treat `env` as either a new in infrastructure, or reuses an existing bicep parameter if one with the same name already exists. -To configure the Azure Container App environment, see [Configure Azure Container Apps environments](configure-aca-environments.md). For more information, see and . +To configure the Azure Container App environment, see [Configure Azure Container Apps environments](configure-aca-environments.md). For information about publishing resources as Azure Container App Jobs, see [Azure Container App Jobs](container-app-jobs.md). For more information, see and . > [!TIP] > If you're working with Azure Container Apps, you might also be interested in the [.NET Aspire Azure Container Registry integration](container-registry-integration.md).