Cloud Tutorial - Creating a Cloud Worker

Show in webframe

Take the following steps to create a worker assembly for the Cloud SDK. This tutorial will assume the objective of this cloud is to convert images from any supported format to PDF using one of the LEADTOOLS Imaging SDK's. This tutorial is meant to be used in conjunction with another tutorial (Adding Jobs To The Cloud), where we demonstrated how to add jobs to the cloud with a custom job type. Now, we will create the worker assembly capable of actually processing these jobs. For simplicity purposes, we will assume the client and worker are on the same machine.

  1. Start Visual Studio

  2. Choose File->New->Project from the menu

  3. In the New Project dialog box, choose either "Visual C# Projects" or "Visual Basic Projects" in the Projects Type List, and choose "Class Library" from the Templates List.

  4. Type the project name as "CloudCreatingWorkersTutorial" in the Project Name field, and then click OK. If desired, type a new location for your project or select a directory using the Browse button, and then click OK.

  5. Change the project build configuration to x86. If this configuration does not exist, add it using the below steps:

    1. Open the configuration manager.

    2. Under 'Platform', choose 'New'.

    3. Choose 'x86' for 'New Platform' and click 'OK'.

  6. In the "Solution Explorer" window, right-click on the "References" folder, and select "Add Reference..." from the context menu. In the "Add Reference" dialog box, select the ".NET" tab and browse to the "<LEADTOOLS_INSTALLDIR>\Bin\DotNet or DotNet4\Win32" folder, and select the following dll's:

    • Leadtools.Cloud.Job
    • Leadtools.dll
    • Leadtools.Codecs.dll
    • Leadtools.Codecs.Bmp.dll
    • Leadtools.Codecs.Cmp.dll
    • Leadtools.Codecs.Tif.dll
    • Leadtools.Codecs.Fax.dll
    • Leadtools.Pdf.Dll
  7. Switch to Class1 code view (Double-click Class1.cs in the solution explorer and add the following lines at the beginning of the file after any Imports or using section if they exists.

    [Visual Basic]

    
                  Imports Leadtools.Cloud.Job
                  Imports System.IO
                  Imports System.Xml.Serialization
                  Imports Leadtools
                  Imports Leadtools.Codecs
                  Imports System.Threading
                       
                  
    

    [C#]

    
                  using Leadtools.Cloud.Job;
                  using System.IO;
                  using System.Xml.Serialization;
                  using Leadtools;
                  using Leadtools.Codecs;
                  using System.Threading;
                       
                  
    
  8. Change the name of the main class to 'MyCustomWorker', and have this class inherit from the JobBase class as shown below.

    
                    Public Class MyCustomWorker : Inherits JobBase
                    End Class
                       
                  
    

    [C#]

    
                    public class MyCustomWorker : JobBase
                    {
                    }
                       
                  
    
  9. Add the following methods, variables and structure to the MyCustomWorker class.

    
                   Public Sub New(ByVal job As IJob)
                      MyBase.New(job)
                      'If using a licensed copy, add your license information below.
                      Dim MY_LICENSE_FILE As String = "d:\temp\TestLic.lic"
                      Dim MY_DEVELOPER_KEY As String = "xyz123abc"
                      RasterSupport.SetLicense(MY_LICENSE_FILE, MY_DEVELOPER_KEY);
                   End Sub
                   'This method will be used to store the conversion settings (source and target file in this simple demo).
                   'The settings were serialized whent he client submitted the job. Now, the worker assembly will deserialize it to obtain the settings.
                   Public Structure JobMetadata
                      Public SourceFile As String
                      Public TargetFile As String
                   
                      Public Sub New(ByVal _sourceFile As String, ByVal _targetFile As String)
                         SourceFile = _sourceFile
                         TargetFile = _targetFile
                      End Sub
                   End Structure
                   Private jobID As String = String.Empty
                   Private loadProgress As Integer = 0
                   Private saveProgress As Integer = 0
                   
                   'Deserialize the JobMetadata
                   Public Function DeserializeFromString(ByVal serializedString As String) As JobMetadata
                      Dim serializedBytes As Byte() = Encoding.Unicode.GetBytes(serializedString)
                      Using ms As MemoryStream = New MemoryStream(serializedBytes)
                         Dim xmlSerializer As XmlSerializer = New XmlSerializer(GetType(JobMetadata))
                         Return CType(xmlSerializer.Deserialize(ms), JobMetadata)
                      End Using
                   End Function
                      
                   Public Overrides Sub OnJobReceived(ByVal id As String, ByVal userToken As String, ByVal jobMetadata As String, ByVal jobType As String, ByVal progressRate As Integer)
                      Try
                         jobID = id
                         loadProgress = 0
                         saveProgress = 0
                      
                         ' Check if we have valid job information and job metadata
                         If String.IsNullOrEmpty(jobMetadata) Then
                            SetFailureStatus(id, CInt(RasterExceptionCode.InvalidParameter), Leadtools.RasterException.GetCodeMessage(RasterExceptionCode.InvalidParameter), Nothing)
                            Return
                         End If
                      
                         'Deserialize the jobMetadata so we can get the conversion settings
                         Dim conversionSettings As JobMetadata = DeserializeFromString(jobMetadata)
                         Using updateStatusTimer As Timer = New Timer(New TimerCallback(AddressOf UpdateStatusProc), Nothing, 0, progressRate * 1000)
                            Using codecs As RasterCodecs = New RasterCodecs()
                               codecs.Options.Save.RetrieveDataFromImage = true           
                               AddHandler codecs.LoadImage, AddressOf Of CodecsLoadImageEventArgs
                               AddHandler codecs.SaveImage, AddressOf Of CodecsSaveImageEventArgs
                               Using img As RasterImage = codecs.Load(conversionSettings.SourceFile)
                                  codecs.Save(img, conversionSettings.TargetFile, Leadtools.RasterImageFormat.RasPdfLzw, 0)
                                  SetCompletedStatus(id, jobMetadata)
                               End Using
                            End Using
                         End Using
                      Catch ex As Exception
                         SetFailureStatus(id, 0, ex.Message, Nothing)
                      End Try
                   End Sub
                   
                   Private Sub codecs_SaveImage(ByVal sender As Object, ByVal e As CodecsSaveImageEventArgs)
                      'Update the save progress
                      saveProgress = e.TotalPercent
                   End Sub
                   
                   Private Sub codecs_LoadImage(ByVal sender As Object, ByVal e As CodecsLoadImageEventArgs)
                      'Update the load progress
                      loadProgress = e.TotalPercent
                   End Sub
                   
                   Private Sub UpdateStatusProc(ByVal stateInfo As Object)
                      Try
                         ' We should always report status when the report status interval elapses otherwise
                         ' the windows service will assume the job hung and the process will be killed
                   
                         'The load and save progress are separate, so we must combine them as 1
                         Dim totalProgress As Integer = (loadProgress / 2) + (saveProgress / 2)
                         UpdatePercentage(jobID, totalProgress, String.Empty)
                      Catch ex As Exception
                         SetFailureStatus(jobID, 0, ex.Message, Nothing)
                      End Try
                   End Sub
                 
                               
    

    [C#]

    
                    public MyCustomWorker(IJob job)
                    : base(job)
                    {
                       //If using a licensed copy, add your license information below.
                       string MY_LICENSE_FILE = "d:\\temp\\TestLic.lic";
                       string MY_DEVELOPER_KEY = "xyz123abc";
                       RasterSupport.SetLicense(MY_LICENSE_FILE, MY_DEVELOPER_KEY);
                    }
                    
                    //This method will be used to store the conversion settings (source and target file in this simple demo).
                    //The settings were serialized whent he client submitted the job. Now, the worker assembly will deserialize it to obtain the settings.
                    public struct JobMetadata
                    {
                       public string SourceFile;
                       public string TargetFile;
                       public JobMetadata(string _sourceFile, string _targetFile)
                       {
                          SourceFile = _sourceFile;
                          TargetFile = _targetFile;
                       }
                    }
                    
                    string jobID = String.Empty;
                    int loadProgress = 0;
                    int saveProgress = 0;
                    
                    //Deserialize the JobMetadata
                    public JobMetadata DeserializeFromString(string serializedString)
                    {
                       byte[] serializedBytes = Encoding.Unicode.GetBytes(serializedString);
                       using (MemoryStream ms = new MemoryStream(serializedBytes))
                       {
                          XmlSerializer xmlSerializer = new XmlSerializer(typeof(JobMetadata));
                          return (JobMetadata)xmlSerializer.Deserialize(ms);
                       }
                    }
                    
                    public override void OnJobReceived(string id, string userToken, string jobMetadata, string jobType, int progressRate)
                    {
                       try
                       {
                          jobID = id;
                          loadProgress = 0;
                          saveProgress = 0;
                          
                          // Check if we have valid job information and job metadata
                          if (String.IsNullOrEmpty(jobMetadata))
                          {
                             SetFailureStatus(id, (int)RasterExceptionCode.InvalidParameter, Leadtools.RasterException.GetCodeMessage(RasterExceptionCode.InvalidParameter), null);
                             return;
                          }
                          
                          //Deserialize the jobMetadata so we can get the conversion settings
                          JobMetadata conversionSettings = DeserializeFromString(jobMetadata);
                          using (Timer updateStatusTimer = new Timer(new TimerCallback(UpdateStatusProc), null, 0, progressRate * 1000))
                          {
                             using (RasterCodecs codecs = new RasterCodecs())
                             {
                                codecs.Options.Save.RetrieveDataFromImage = true;
                                codecs.LoadImage += new EventHandler<CodecsLoadImageEventArgs>(codecs_LoadImage);
                                codecs.SaveImage += new EventHandler<CodecsSaveImageEventArgs>(codecs_SaveImage);
                                using (RasterImage img = codecs.Load(conversionSettings.SourceFile))
                                {
                                   codecs.Save(img, conversionSettings.TargetFile, Leadtools.RasterImageFormat.RasPdfLzw, 0);
                                   SetCompletedStatus(id, jobMetadata);
                                }
                             }
                          }
                       }
                       catch (Exception ex)
                       {
                          SetFailureStatus(id, 0, ex.Message, null);
                       }
                    }
                    void codecs_SaveImage(object sender, CodecsSaveImageEventArgs e)
                    {
                       //Update the save progress
                       saveProgress = e.TotalPercent;
                    }
                    void codecs_LoadImage(object sender, CodecsLoadImageEventArgs e)
                    {
                       //Update the load progress
                       loadProgress = e.TotalPercent;
                    }
                    
                    private void UpdateStatusProc(Object stateInfo)
                    {
                       try
                       {
                          // We should always report status when the report status interval elapses otherwise
                          // the windows service will assume the job hung and the process will be killed
                       
                          //The load and save progress are separate, so we must combine them as 1
                          int totalProgress = (loadProgress / 2) + (saveProgress / 2);
                          UpdatePercentage(jobID, totalProgress, String.Empty);
                       }
                       catch (Exception ex)
                       {
                          SetFailureStatus(jobID, 0, ex.Message, null);
                       }
                    }
                                
    
  10. The Workers.config for the WorkerService WCF Service needs to be updated to handle this type of job. Follow the below steps to update the file.

    1. Open Workers.xml in the App_Data directory of the WorkerService WCF Service.

    2. Add the new job type under the machine that will be the worker (see below). In Adding Jobs To The Cloud, we used a custom job type of 'ConvertToPDF' so we need to use the same job type here.


      Add the new job type under the machine that will be the worker (see below). In Adding Jobs To The Cloud, we used a custom job type of 'ConvertToPDF' so we need to use the same job type here. <Workers> <Worker Name="MachineName" NewJobCheckPeriod="2"> <JobTypes> <JobType Name="ConvertToPDF" MaxNumberOfJobs="5" CpuThreshold="80" UseCpuThreshold="false" ProgressRate="10" AssumeHangAfter="60" Attempts="3"/> </JobTypes> </Worker> </Workers>
  11. Now we need to update the windows service configuration file on the worker (app.config) with the new job type, and some information about our new assembly (see below for example). Follow the below steps to update the file.

    1. Open the windows service configuration file on the worker (app.config).

    2. Update the 'JobType' to 'ConvertToPDF'.

    3. Update the 'UserDllPath' so that it points to the location of your customer worker assembly.

    4. Update the 'UserClassTypeName' to the name of the namespace and class in your worker assembly that will do the work (CloudCreatingWorkersTutorial.MyCustomWorker).


    Now we need to update the windows service configuration file on the worker (app.config) with the new job type, and some information about our new assembly (see below for example). Follow the below steps to update the file.
    Open the windows service configuration file on the worker (app.config).
    Update the 'JobType' to 'ConvertToPDF'.
    Update the 'UserDllPath' so that it points to the location of your customer worker assembly.
    Update the 'UserClassTypeName' to the name of the namespace and class in your worker assembly that will do the work (CloudCreatingWorkersTutorial.MyCustomWorker). <userSettings> <Leadtools.Cloud.WorkerService.Properties.Settings> <setting name="UserClassTypeName" serializeAs="String"> <value>CloudCreatingWorkersTutorial.MyCustomWorker</value> </setting> <setting name="JobType" serializeAs="String"> <value>ConvertToPDF</value> </setting> <setting name="WorkerLayerPath" serializeAs="String"> <value>Path to Leadtools.Cloud.Workerlayer.exe</value> </setting> <setting name="UserDllPath" serializeAs="String"> <value>Path to your worker assembly</value> </setting> </Leadtools.Cloud.WorkerService.Properties.Settings> </userSettings>
  12. The worker assembly is now ready to process jobs. If you have not already done so, add jobs to the cloud using the project you created in Adding Jobs To The Cloud. Once jobs are added, start the windows service on the worker so that it can begin processing jobs.

    NOTE: If you encounter an "Invalid File Format" or "Feature Not Supported" exception, please refer to the topic Invalid File Format/Feature Not Supported.

References

LEADTOOLS Cloud Settings
Understanding The LEADTOOLS Cloud Database
Creating Cloud Worker Assemblies
Deploying LEADTOOLS Cloud
Unlocking Special LEAD Features

 

 


Products | Support | Contact Us | Copyright Notices
© 2006-2014 All Rights Reserved. LEAD Technologies, Inc.