Skip to content

Commit c0f8e7f

Browse files
committed
Update C# HelloWorld sample to track 2
1 parent 17fa81b commit c0f8e7f

File tree

6 files changed

+172
-236
lines changed

6 files changed

+172
-236
lines changed

CSharp/GettingStarted/01_HelloWorld/HelloWorld.csproj

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,14 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>net462</TargetFramework>
6-
<RootNamespace>Microsoft.Azure.Batch.Samples.HelloWorld</RootNamespace>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<RootNamespace>Azure.Compute.Batch.Samples.HelloWorld</RootNamespace>
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<ProjectReference Include="..\..\Common\Microsoft.Azure.Batch.Samples.Common.csproj" />
11-
</ItemGroup>
12-
13-
<ItemGroup>
14-
<PackageReference Include="Microsoft.Azure.Batch" Version="14.0.0" />
15-
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="2.1.0" />
16-
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.1.0" />
17-
<PackageReference Include="WindowsAzure.Storage" Version="9.3.3" />
18-
</ItemGroup>
19-
20-
<ItemGroup>
21-
<None Update="settings.json">
22-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
23-
</None>
10+
<PackageReference Include="Azure.Compute.Batch" Version="1.0.0-beta.3" />
11+
<PackageReference Include="Azure.Identity" Version="1.14.1" />
12+
<PackageReference Include="Azure.ResourceManager.Batch" Version="1.5.0" />
2413
</ItemGroup>
2514

2615
</Project>
Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio 15
4-
VisualStudioVersion = 15.0.26430.12
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.9.34728.123
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelloWorld", "HelloWorld.csproj", "{FE62D509-B9A9-4592-81BB-779306C22F95}"
77
EndProject
8-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Batch.Samples.Common", "..\..\Common\Microsoft.Azure.Batch.Samples.Common.csproj", "{612B170A-1697-4C40-BD57-26A6C8AC6534}"
9-
EndProject
108
Global
119
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1210
Debug|Any CPU = Debug|Any CPU
@@ -17,12 +15,11 @@ Global
1715
{FE62D509-B9A9-4592-81BB-779306C22F95}.Debug|Any CPU.Build.0 = Debug|Any CPU
1816
{FE62D509-B9A9-4592-81BB-779306C22F95}.Release|Any CPU.ActiveCfg = Release|Any CPU
1917
{FE62D509-B9A9-4592-81BB-779306C22F95}.Release|Any CPU.Build.0 = Release|Any CPU
20-
{612B170A-1697-4C40-BD57-26A6C8AC6534}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21-
{612B170A-1697-4C40-BD57-26A6C8AC6534}.Debug|Any CPU.Build.0 = Debug|Any CPU
22-
{612B170A-1697-4C40-BD57-26A6C8AC6534}.Release|Any CPU.ActiveCfg = Release|Any CPU
23-
{612B170A-1697-4C40-BD57-26A6C8AC6534}.Release|Any CPU.Build.0 = Release|Any CPU
2418
EndGlobalSection
2519
GlobalSection(SolutionProperties) = preSolution
2620
HideSolutionNode = FALSE
2721
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {33B77A65-5D1C-46B7-918E-D922919D6884}
24+
EndGlobalSection
2825
EndGlobal
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
3+
using Azure.Core;
4+
using Azure.Identity;
5+
using Azure.ResourceManager;
6+
using Azure.ResourceManager.Batch;
7+
using Azure.ResourceManager.Batch.Models;
8+
using System;
9+
using System.IO;
10+
using System.Linq;
11+
using System.Threading.Tasks;
12+
13+
namespace Azure.Compute.Batch.Samples.HelloWorld
14+
{
15+
public class HelloWorldSample
16+
{
17+
private ArmClient _armClient;
18+
private BatchClient _batchClient;
19+
20+
/// <summary>
21+
/// Creates a pool with a configurable number of nodes, then submits tasks which print a 'Hello world' message.
22+
/// The resulting stdout.txt or stderr.txt (depending on each task's exit code) is then printed to the console.
23+
///
24+
/// After running, the job will be terminated and the pool will be deleted.
25+
/// </summary>
26+
/// <param name="batchAccountResourceId">The ARM resource ID of the Batch account.</param>
27+
/// <returns>A task which completes when the sample has finished running.</returns>
28+
public async Task Run(string batchAccountResourceId)
29+
{
30+
var batchAccountIdentifier = ResourceIdentifier.Parse(batchAccountResourceId);
31+
32+
var credential = new DefaultAzureCredential();
33+
_armClient = new ArmClient(credential);
34+
35+
BatchAccountResource batchAccount = await _armClient.GetBatchAccountResource(batchAccountIdentifier).GetAsync();
36+
37+
_batchClient = new BatchClient(new Uri($"https://{batchAccount.Data.AccountEndpoint}"), credential);
38+
39+
var poolName = GenerateUniqueName("HelloWorldPool");
40+
var imageReference = new BatchImageReference()
41+
{
42+
Publisher = "canonical",
43+
Offer = "0001-com-ubuntu-server-jammy",
44+
Sku = "22_04-lts",
45+
Version = "latest"
46+
};
47+
string nodeAgentSku = "batch.node.ubuntu 22.04";
48+
int targetDedicatedNodes = 1;
49+
50+
Console.WriteLine("Creating pool {0} with {1} dedicated {2} in account {3}", poolName, targetDedicatedNodes, targetDedicatedNodes == 1 ? "node" : "nodes", batchAccount.Data.Name);
51+
BatchAccountPoolResource pool = (await batchAccount.GetBatchAccountPools().CreateOrUpdateAsync(WaitUntil.Completed, poolName, new BatchAccountPoolData()
52+
{
53+
VmSize = "Standard_DS1_v2",
54+
DeploymentConfiguration = new BatchDeploymentConfiguration()
55+
{
56+
VmConfiguration = new BatchVmConfiguration(imageReference, nodeAgentSku)
57+
},
58+
ScaleSettings = new BatchAccountPoolScaleSettings()
59+
{
60+
FixedScale = new BatchAccountFixedScaleSettings()
61+
{
62+
TargetDedicatedNodes = targetDedicatedNodes
63+
}
64+
}
65+
})).Value;
66+
67+
string jobId = GenerateUniqueName("HelloWorldJob");
68+
69+
try
70+
{
71+
Console.WriteLine("Creating job {0}", jobId);
72+
await _batchClient.CreateJobAsync(new BatchJobCreateOptions(jobId, new BatchPoolInfo() { PoolId = poolName }));
73+
74+
for (int i = 0; i < 5; i++)
75+
{
76+
string taskId = $"task-{i}";
77+
Console.WriteLine("Submitting {0}", taskId);
78+
await _batchClient.CreateTaskAsync(jobId, new BatchTaskCreateOptions(taskId, $"echo Hello world from {taskId}"));
79+
}
80+
81+
Console.WriteLine("Waiting for all tasks to complete...");
82+
await waitForTasksToComplete(jobId);
83+
84+
var completedTasks = _batchClient.GetTasksAsync(jobId, filter: "state eq 'completed'");
85+
await foreach (BatchTask t in completedTasks)
86+
{
87+
var outputFileName = t.ExecutionInfo.ExitCode == 0 ? "stdout.txt" : "stderr.txt";
88+
89+
Console.WriteLine("Task {0} exited with code {1}. Output ({2}):",
90+
t.Id, t.ExecutionInfo.ExitCode, outputFileName);
91+
92+
BinaryData fileContents = await _batchClient.GetTaskFileAsync(jobId, t.Id, outputFileName);
93+
using (var reader = new StreamReader(fileContents.ToStream()))
94+
{
95+
Console.WriteLine(await reader.ReadLineAsync());
96+
}
97+
}
98+
}
99+
finally
100+
{
101+
Console.WriteLine("Terminating job and deleting pool");
102+
await Task.WhenAll([
103+
_batchClient.TerminateJobAsync(jobId),
104+
pool.DeleteAsync(WaitUntil.Completed)]);
105+
}
106+
}
107+
108+
/// <summary>
109+
/// Poll all the tasks in the given job and wait for them to reach the completed state.
110+
/// </summary>
111+
/// <param name="jobId">The ID of the job to poll</param>
112+
/// <returns>A task that will complete when all Batch tasks have completed.</returns>
113+
/// <exception cref="TimeoutException">Thrown if all tasks haven't reached the completed state after a certain period of time</exception>
114+
private async Task waitForTasksToComplete(String jobId)
115+
{
116+
// Note that this timeout should take into account the time it takes for the pool to scale up
117+
var timeoutAfter = DateTime.Now.AddMinutes(10);
118+
while (DateTime.Now < timeoutAfter)
119+
{
120+
var allComplete = true;
121+
var tasks = _batchClient.GetTasksAsync(jobId, select: ["id", "state"]);
122+
await foreach (BatchTask task in tasks)
123+
{
124+
if (task.State != BatchTaskState.Completed)
125+
{
126+
allComplete = false;
127+
break;
128+
}
129+
}
130+
131+
if (allComplete)
132+
{
133+
return;
134+
}
135+
136+
await Task.Delay(10000);
137+
}
138+
139+
throw new TimeoutException("Task(s) did not complete within the specified time");
140+
}
141+
142+
/// <summary>
143+
/// Generate a unique name with the given prefix using the current user name and a timestamp.
144+
/// </summary>
145+
/// <param name="prefix">The name's prefix.</param>
146+
/// <returns>The generated name.</returns>
147+
private static string GenerateUniqueName(string prefix)
148+
{
149+
string currentUser = new string(Environment.UserName.Where(char.IsLetterOrDigit).ToArray());
150+
return string.Format("{0}-{1}-{2}", prefix, currentUser, DateTime.Now.ToString("yyyyMMdd-HHmmss"));
151+
}
152+
}
153+
}

0 commit comments

Comments
 (0)