Tutorial 1: Using the DSL
The purpose of this tutorial is to use the Toolkit DSL to define a very simple workload and submit it.
When you are done, you should have:
- An understanding of the basic object model of workloads
- An understanding of some operations that are supported by the toolkit
- An experience of having interacted with the Batch Service and submitted your first workload
Remember, you should have run the Getting Set Up tutorial first!
Reference and Namespace
The first thing to do is to reference the toolkit. Note that it is packaged in Batch.Toolkit.dll
The next thing is to open the namespace. Note that this is Batch.Toolkit
The DSL is found in the
1: 2: 3: |
|
Object Model: Command
A Command is the basic unit of execution. This is typically the name of your executable file or batch script.
The object model defined in the toolkit has two kinds of commands:
- A
SimpleCommandis just a string with the command line of the executable you want to run. You can have spaces and static arguments passed to the executable name as part of a simple command - A
ParametrizedCommandpairs a command line template with a collection of parameter names, which can be replaced by the toolkit with a range of values. Surround the parameter name with%in the command line to identify it as a placeholder.
The following let creates an instance of a ParametrizedCommand through the DSL shortcut :parametric_cmd.
1:
|
|
Note that the double backticks around :parametric_cmd - and around all the DSL keywords - are required.
As you probably imagine, this command will eventually be expressed as a different command-line for each value that we might bind to user.
Object Model: WorkloadUnitTemplate
We can compose commands into more complex objects in the toolkit, but the one that is ultimately useful for us is the WorkloadUnitTemplate object.
For now, let's skip discussing the intermediate objects and build one from our command using the :unit_template "keyword" from the DSL.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: |
|
The key components of the :unit_template are:
- The
:adminflag: This specifies if the commands in the template require administrative privileges to run. - The
:mainblock: This is a list ofCommands which are composed together to run. We only have one here, which says that we want to:dothehelloUserCommandspecified earlier without any error handling. - The
:finallyblock: This is a list ofCommands which we require to be run at the end of the main block. We won't need to run anything here for this simple workload. - The
:filesblock: This is a list ofFileInfoobjects representing files we want to upload in order to run the workload successfully. We don't need any files for this simple workload.
Object Model: Workload
Now, let's specify a Workload, which will represent a Batch Job. We can do this by using the :workload DSL command.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: |
|
A :workload is associated with the following:
- A
:unit_templatesblock: This is a collection ofWorkloadUnitTemplates associated with thisWorkload. Our example uses the single template we defined earlier. - A
:filesblock: This is a list ofFileInfoobjects which represents the files common to all the instances of all theWorkloadUnitTemplates in this workload. - An
:argumentsblock: This is a collection of named:ranges, which specify the set of values for each parameter.
A new instance of each WorkloadUnitTemplate is created and bound to each unique set of arguments, and these instances form the Tasks in our Batch Job.
In this example, the Workload will be expressed into a single Batch Job with three tasks: one for each value of user specified in the :range.
Now we are done with the definition, and all we need to do is to run the workload on the Batch Service.
Object Model : Configuration Objects
Interacting with the Batch service requires us to pass some credentials to in order to obtain a set of correctly configured context objects against which we can operate.
The toolkit has defined a few configuration objects (and helper methods to read these objects in from JSON files) so we can easily write applications and manage the credentials sensibly.
- BatchConfiguration
1: 2: 3: 4: 5: 6: |
|
- StorageConfiguration
1: 2: 3: 4: 5: |
|
There is also a helper function readConfig<'a> which can construct an 'a from an appropriately written JSON file.
We can now build these objects from our JSON files like so:
1: 2: 3: 4: 5: 6: |
|
Object Model : Pool Object
Azure Batch is remarkable in its approach to providing a Batch execution context in that it separates the concern of Resource Allocation from the concern of Job Management. We have focussed in this sample on defining the Job in a user-centric way, but in order to run the job, we require a Pool.
Azure Batch allows us to specify an automatic pool, or to re-use a named pool. In our example, we'll use a named pool and the Toolkit infrastructure will create one for us if it doesn't exist already.
1:
|
|
Now we can run the workload we've created, and the task representing the helloUserCommand for each respective user will be executed on a virtual machine managed by the pool.
1:
|
|
Finishing touches
We can, in fact, make a utility function to run any workload against our configuration files, and re-use that for all our samples:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: |
|
The whole enchilada
Using this utility function, we can focus purely on defining our workload in our main sample.
The whole sample looks like this:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: |
|
Just one of the 30 lines of code above is the act of running the workload. The remaining code is entirely focussed on defining the workload itself.
Summary
We were able to model a workload with a parametric sweep and execute it against Azure Batch using a little DSL in the Toolkit.
The key take-aways are:
- It's useful to be able to take a workload-centric view of the problem, and abstract away the interaction with the Azure Batch Service (via the Azure Batch Client SDK).
- We have an object model that allows us to think about composing smaller pieces together to make more complex workloads.
- We have a little DSL that allows us to hide even the creation of the object model instances in a pleasant (if idiosyncratic) manner.
- Specifically, this model (and the DSL) supports a way to sweep a set of values over a set of parameters to build a set of batch tasks.
Hope you have fun playing around with the DSL. You'll find the other supported operations here.
Enjoy!
from Batch.Toolkit
Full name: Tutorial1.helloUserCommand
Full name: Batch.Toolkit.DSL.( :parametric_cmd )
Full name: Batch.Toolkit.DSL.( :with_params )
Full name: Tutorial1.workloadUnitTemplate
Full name: Batch.Toolkit.DSL.( :unit_template )
Full name: Batch.Toolkit.DSL.( :admin )
Full name: Batch.Toolkit.DSL.( :main )
Full name: Batch.Toolkit.DSL.( :do )
Full name: Batch.Toolkit.DSL.( :finally )
Full name: Batch.Toolkit.DSL.( :files )
Full name: Tutorial1.workload
Full name: Batch.Toolkit.DSL.( :workload )
Full name: Batch.Toolkit.DSL.( :unit_templates )
Full name: Batch.Toolkit.DSL.( :arguments )
Full name: Batch.Toolkit.DSL.( :range )
Full name: Batch.Toolkit.DSL.( :over )
{BatchAccountName: string;
BatchAccountKey: string;
BatchAccountRegion: string;
BatchServiceUri: string;}
Full name: Tutorial1.BatchConfiguration
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = System.String
Full name: Microsoft.FSharp.Core.string
{StorageAccountName: string;
StorageAccountKey: string;
StagingContainerName: string;}
Full name: Tutorial1.StorageConfiguration
Full name: Tutorial1.batchConfig
Full name: Tutorial1.storageConfig
Full name: Batch.Toolkit.SuccessOrFailure.succeed
Full name: Batch.Toolkit.Common.readConfig
Full name: Batch.Toolkit.SuccessOrFailure.getOrThrow
Full name: Tutorial1.pool
union case Pool.NamedPool: NamedPool -> Pool
--------------------
type NamedPool =
{NamedPoolName: PoolName;
NamedPoolSpecification: PoolSpecification;}
Full name: Batch.Toolkit.NamedPool
union case PoolName.PoolName: string -> PoolName
--------------------
type PoolName = | PoolName of string
Full name: Batch.Toolkit.PoolName
from Batch.Toolkit
Full name: Batch.Toolkit.PoolOperations.GetDefaultPoolSpecification
from Batch.Toolkit
Full name: Batch.Toolkit.WorkloadOperations.RunWorkloadOnPool
Full name: Tutorial1.SampleCommon.runSampleWorkload
from Tutorial1
Full name: Tutorial1.Sample1.helloUserCommand
Full name: Tutorial1.Sample1.workloadUnitTemplate
Full name: Tutorial1.Sample1.workload