-
Notifications
You must be signed in to change notification settings - Fork 10
Simple Usage
To just use the whole system to distribute a job, the following points need to be done:
- Create input/output/settings objects
- Create a handler
- Create a job script
- Upload package
- Upload job script
There are three objects (classes) which are needed by the server and a handler.
The input object contains the individual values a job needs to run. It needs to be serializable by Json.Net and implement the decorator interface IJobInput
.
An easy example for a simple calculator would be:
public class CalculatorJobInput : IJobInput
{
public int Number1 { get; set; }
public int Number2 { get; set; }
}
The output object contains the result of the job. It also needs to be serializable by Json.Net and implement the decorator interface IJobOutput
.
An easy example for a simple calculator would be:
public class CalculatorJobOutput : IJobOutput
{
public int Result { get; set; }
}
Since multiple job scripts can use the same handler, there might be a need for small differences in the handlers for the different job scripts. To achieve this, there is a customizable settings object which is defined per job script and can be used to change the behavior of the handler. It also needs to be serializable by Json.Net and implement the decorator interface IHandlerCustomSettings
.
An easy example for a simple calculator would be:
public class CalculatorHandlerSettings : IHandlerCustomSettings
{
public bool NegateResult { get; set; }
}
The handler contains the server code. It's main features are to generate jobs and process the results.
The handler class itself needs the attribute HandlerNameAttribute
to define a unique name for the handler.
Furthermore it needs to be based on the class HandlerBase
, which is a generic class and uses the settings, input and output classes defined before as generic types.
The simple example for the calculator could look like:
[HandlerNameAttribute("Calculator")]
public class CalculatorHandler : HandlerBase<CalculatorHandlerSettings, CalculatorJobInput, CalculatorJobOutput>
{
public override void Initialize()
{
Logger.Debug("NegateResult: {0}", Settings.NegateResult);
}
public override void CreateMoreJobs()
{
var random = new Random();
for (var i = 0; i < 50; i++)
{
EnqueueJob(new CalculatorJobInput(random.Next(10), random.Next(100)));
}
}
public override void ProcessResult(CalculatorJobInput jobInput, CalculatorJobOutput jobResult)
{
Logger.Info("Result: {0}", jobResult.Result * (Settings.NegateResult ? -1 : 1));
}
}
The job script is one csharp file which has three main components. All those three components combined in one file form a complete job script file.
A handler for a job has some default settings (like name, handler to use, scheduler, ...) and,
as mentioned before, can have custom settings. To initialize those settings in a type save way, a handler initializer class needs to be created. It needs to be based on the class HandlerInitializerBase
which is a generic of the type of the custom settings created earlier.
Then the two methods to fill the default settings object and the custom settings object need do be overridden.
For our calculator, this could look like:
public class CalculatorAddHandlerInitializer : HandlerInitializerBase<CalculatorHandlerSettings>
{
public override void FillHandlerSettings(HandlerSettings handlerSettings)
{
handlerSettings.HandlerName = "Calculator";
handlerSettings.JobName = "Calculator - Add";
handlerSettings.AutoStart = true;
handlerSettings.Schedule = "* * * * *";
}
public override void FillCustomSettings(CalculatorHandlerSettings customSettings)
{
customSettings.NegateResult = true;
}
}
The job script contains the code which is executed on the client. It needs to be based on the class JobScriptBase
and takes the earlier created input and output class as the generic types.
All it then needs to do is override the Process
method and create the output object from the input object.
For our calculator this could look like:
public class CalculatorJobScriptAdd : JobScriptBase<CalculatorJobInput, CalculatorJobOutput>
{
public override CalculatorJobOutput Process(CalculatorJobInput input)
{
var result = new CalculatorJobOutput { Result = input.Number1 + input.Number2 };
return result;
}
}
Since this job script is compiled on the fly out of the correct package, there are several information that we need to define. This information are provided within precompiler directives (which are never hit). There are three things which need to be defined:
- Libraries needed to compile this class
- Additional dependencies which are downloaded from the server before compiling / running
- The name of the package In our calculator, this could look like:
#if NETDISTCOMPILERLIBRARIES
System.dll
NetDist.Jobs.dll
SimpleCalculator.dll
#endif
#if NETDISTDEPENDENCIES
SimpleCalculator.dll
#endif
#if NETDISTPACKAGE
SimpleCalculator
#endif
Now all the parts are ready to be deployed. The package contains all files needed that the server and the client need to execute. So the server needs a list of files which include handlers (marked by the attribute), a list of dependencies (which are used by the server and/or the client) and a name for the package. This can be done by simply using the server admin tool.
Now that the package is ready, the job script can be uploaded. To upload this, just use the server admin tool as well. If everything is ok, you should now see the new job in the server admin tool and it is now able to run and distribute jobs.