Skip to content
Roman edited this page Feb 4, 2015 · 2 revisions

To just use the whole system to distribute a job, the following points need to be done:

  1. Create input/output/settings objects
  2. Create a handler
  3. Create a job script
  4. Upload package
  5. Upload job script

1. Create input/output/settings objects

There are three objects (classes) which are needed by the server and a handler.

Input

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; }
}
Output

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; }
}
Settings

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; }
}

2. Create a handler

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));
	}
}

3. Create a job script

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.

Handler initializer

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;
	}
}
Job Script

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;
	}
}
Meta information

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

4. Upload package

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.

5. Upload job script

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.