Cloning a Job
If you want to run a job multiple times (you cannot rerun a finished job or move it back to the configuring state) or if you want to create variations of a job, call the IScheduler::CloneJob method to create a job that is a copy of the specified job.
The CloneJob method copies all the tasks (includes the instances for parametric tasks) and a subset of the job and task property values. For a list of the properties that the method copies, see the Remarks section for the CloneJob method.
You can clone a job that is in any state; however, only the owner of the job can clone the job.
If a job fails, you can either clone the job (if you want to save its state) or you can call the IScheduler::ConfigureJob method to move the job back to the configuring state to fix the cause of the error.
The following C# example shows how to clone a job, change the properties on the existing tasks, add a new task, and submit the new job.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Hpc.Scheduler;
using Microsoft.Hpc.Scheduler.Properties;
namespace CloneJob
{
class Program
{
private static IScheduler m_scheduler = null;
static void Main(string[] args)
{
ISchedulerJob clonedJob = null;
int jobId = 0;
try
{
m_scheduler = new Scheduler();
m_scheduler.Connect("localhost");
jobId = CreateJob();
PrintTasks(m_scheduler.OpenJob(jobId));
clonedJob = m_scheduler.CloneJob(jobId);
PrintTasks(m_scheduler.OpenJob(clonedJob.Id));
UpdateClonedJob(clonedJob);
PrintTasks(m_scheduler.OpenJob(clonedJob.Id));
m_scheduler.SubmitJob(clonedJob, @"<USERNAMEGOESHERE>", null);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
// Creates a job, adds a task and a parametric task to the job, and
// then submits the job.
private static int CreateJob()
{
ISchedulerJob job = null;
ISchedulerTask task = null;
job = m_scheduler.CreateJob();
// Create a parametric task
task = job.CreateTask();
task.CommandLine = @"echo *";
task.IsParametric = true;
task.StartValue = 1;
task.EndValue = 5;
task.IncrementValue = 1;
job.AddTask(task);
// Create a task
task = job.CreateTask();
task.CommandLine = @"ping <COMPUTERNAMEGOESHERE>";
job.AddTask(task);
m_scheduler.SubmitJob(job, @"<USERNAMEGOESHERE>", null);
return job.Id;
}
// Print the tasks IDs of the tasks in the job. Include StdOut
// to show the update to the tasks.
private static void PrintTasks(ISchedulerJob job)
{
Console.WriteLine("Tasks for job " + job.Id);
foreach (ISchedulerTask task in job.GetTaskList(null, null, true))
{
Console.WriteLine("id({0}), instance({1}), job({2})",
task.TaskId.JobTaskId, task.TaskId.InstanceId, task.TaskId.ParentJobId);
Console.WriteLine("\tcommand: " + task.CommandLine);
Console.WriteLine("\tstdout: " + task.StdOutFilePath);
}
Console.WriteLine();
}
// Update the cloned job. Add StdOut path to capture output from tasks.
// Add a new task to the job.
private static void UpdateClonedJob(ISchedulerJob job)
{
ISchedulerTask task = null;
ITaskId taskId = null;
// Get the parametric task. Update the start value and
// set the stdout path.
taskId = m_scheduler.CreateTaskId(1);
task = job.OpenTask((TaskId)taskId);
task.StartValue = 3;
task.StdOutFilePath = @"<PATHGOESHERE>\echo_inst*.txt";
task.Commit();
// Add a new task to the job.
task = job.CreateTask();
task.CommandLine = @"echo 'new task'";
task.StdOutFilePath = @"<PATHGOESHERE>\new.txt";
job.AddTask(task);
}
}
}
The following C++ example shows how to clone a job, change the properties on the existing tasks, add a new task, and submit the new job.
#include <windows.h>
#include <stdio.h>
// The Microsoft.Hpc.Scheduler.tlb and Microsoft.Hpc.Scheduler.Properties.tlb type
// libraries are included in the Microsoft HPC Pack 2008 SDK. The type libraries are
// located in the "Microsoft HPC Pack 2008 SDK\Lib\i386" or \amd64 folder. Include the rename
// attributes to avoid name collisions.
#import <Microsoft.Hpc.Scheduler.tlb> named_guids no_namespace raw_interfaces_only \
rename("SetEnvironmentVariable","SetHpcEnvironmentVariable") \
rename("AddJob", "AddHpcJob")
#import <Microsoft.Hpc.Scheduler.Properties.tlb> named_guids no_namespace raw_interfaces_only
IScheduler* g_pScheduler = NULL;
long CreateJob(void);
void PrintTasks(int JobId);
void UpdateClonedJob(int JobId);
void wmain(int argc, WCHAR *argv[])
{
HRESULT hr = S_OK;
ISchedulerJob* pClonedJob = NULL;
long JobId = 0;
long ClonedJobId = 0;
// Use the apartment-threaded model to ensure the code is thread safe.
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
// Get an instance of the Scheduler object.
hr = CoCreateInstance( __uuidof(Scheduler), // CLSID_Scheduler,
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IScheduler), // IID_IScheduler,
reinterpret_cast<void **> (&g_pScheduler) );
if (FAILED(hr))
{
wprintf(L"CoCreateInstance(IScheduler) failed with 0x%x.\n", hr);
goto cleanup;
}
hr = g_pScheduler->Connect(_bstr_t(L"localhost"));
if (FAILED(hr))
{
wprintf(L"Unable to connect to localhost. Failed with 0x%x.\n", hr);
goto cleanup;
}
wprintf(L"Connected to localhost\n");
JobId = CreateJob();
if (JobId)
{
PrintTasks(JobId);
hr = g_pScheduler->CloneJob(JobId, &pClonedJob);
if (FAILED(hr))
{
wprintf(L"g_pScheduler->CloneJob failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pClonedJob->get_Id(&ClonedJobId);
PrintTasks(ClonedJobId);
UpdateClonedJob(ClonedJobId);
PrintTasks(ClonedJobId);
hr = g_pScheduler->SubmitJobById(ClonedJobId, _bstr_t(L"<USERNAMEGOESHERE>"), NULL);
if (FAILED(hr))
{
wprintf(L"g_pScheduler->SubmitJobById failed with 0x%x.\n", hr);
goto cleanup;
}
}
cleanup:
// Before exiting, release your instance of IScheduler.
if (g_pScheduler)
g_pScheduler->Release();
if (pClonedJob)
pClonedJob->Release();
CoUninitialize();
}
long CreateJob(void)
{
HRESULT hr = S_OK;
ISchedulerJob* pJob = NULL;
ISchedulerTask* pTask = NULL;
long JobId = 0;
hr = g_pScheduler->CreateJob(&pJob);
if (FAILED(hr))
{
wprintf(L"g_pScheduler->CreateJob failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pJob->CreateTask(&pTask);
if (FAILED(hr))
{
wprintf(L"pJob->CreateTask failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pTask->put_CommandLine(_bstr_t(L"echo *"));
if (FAILED(hr))
{
wprintf(L"pTask->put_CommandLine failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pTask->put_IsParametric(VARIANT_TRUE);
hr = pTask->put_StartValue(1);
hr = pTask->put_EndValue(5);
hr = pTask->put_IncrementValue(1);
hr = pJob->AddTask(pTask);
if (FAILED(hr))
{
wprintf(L"pTask->AddTask failed with 0x%x.\n", hr);
goto cleanup;
}
pTask->Release();
pTask = NULL;
hr = pJob->CreateTask(&pTask);
if (FAILED(hr))
{
wprintf(L"pJob->CreateTask failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pTask->put_CommandLine(_bstr_t(L"ping <COMPUTERNAMEGOESHERE>"));
if (FAILED(hr))
{
wprintf(L"pTask->put_CommandLine failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pJob->AddTask(pTask);
if (FAILED(hr))
{
wprintf(L"pJob->AddTask failed with 0x%x.\n", hr);
goto cleanup;
}
hr = g_pScheduler->SubmitJob(pJob, _bstr_t("<USERNAMEGOESHERE>"), NULL);
if (FAILED(hr))
{
wprintf(L"g_pScheduler->SubmitJob failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pJob->get_Id(&JobId);
cleanup:
if (pJob)
pJob->Release();
if (pTask)
pTask->Release();
return JobId;
}
void PrintTasks(int JobId)
{
HRESULT hr = S_OK;
ISchedulerJob* pJob = NULL;
ISchedulerTask* pTask = NULL;
ISchedulerCollection* pCollection = NULL;
ITaskId* pTaskId = NULL;
_variant_t var;
long JobTaskId = 0;
long InstanceId = 0;
long Count = 0;
_bstr_t bstrCommand;
_bstr_t bstrStdOut;
wprintf(L"Tasks for job %d\n", JobId);
hr = g_pScheduler->OpenJob(JobId, &pJob);
if (FAILED(hr))
{
wprintf(L"g_pScheduler->OpenJob failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pJob->GetTaskList(NULL, NULL, VARIANT_TRUE, &pCollection);
if (FAILED(hr))
{
wprintf(L"pJob->GetTaskList failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pCollection->get_Count(&Count);
for (long i = 0; i < Count; i++)
{
hr = pCollection->get_Item(i, &var);
if (FAILED(hr))
{
wprintf(L"pCollection->get_Item failed with 0x%x.\n", hr);
goto cleanup;
}
hr = var.pdispVal->QueryInterface(IID_ISchedulerTask, reinterpret_cast<void**>(&pTask));
hr = pTask->get_TaskId(&pTaskId);
if (FAILED(hr))
{
wprintf(L"pTask->get_TaskId failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pTaskId->get_JobTaskId(&JobTaskId);
hr = pTaskId->get_InstanceId(&InstanceId);
wprintf(L"id(%d), instance(%d), job(%d)\n", JobTaskId, InstanceId, JobId);
hr = pTask->get_CommandLine(&(bstrCommand.GetBSTR()));
if (FAILED(hr))
{
wprintf(L"pTask->get_CommandLine failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pTask->get_StdOutFilePath(&(bstrStdOut.GetBSTR()));
if (FAILED(hr))
{
wprintf(L"pTask->get_StdOutFilePath failed with 0x%x.\n", hr);
goto cleanup;
}
wprintf(L"\tCommand: %s\n\tStdOut: %s\n", bstrCommand.GetBSTR(), bstrStdOut.GetBSTR());
pTask->Release();
pTask = NULL;
pTaskId->Release();
pTaskId = NULL;
}
wprintf(L"\n");
cleanup:
if (pJob)
pJob->Release();
if (pTask)
pTask->Release();
if (pTaskId)
pTaskId->Release();
if (pCollection)
pCollection->Release();
}
void UpdateClonedJob(int JobId)
{
HRESULT hr = S_OK;
ISchedulerJob* pJob = NULL;
ISchedulerTask* pTask = NULL;
ISchedulerCollection* pCollection = NULL;
ITaskId* pTaskId = NULL;
hr = g_pScheduler->OpenJob(JobId, &pJob);
if (FAILED(hr))
{
wprintf(L"g_pScheduler->OpenJob failed with 0x%x.\n", hr);
goto cleanup;
}
// Get the parametric task. Change the start
// value and set the stdout path.
hr = g_pScheduler->CreateTaskId(1, &pTaskId);
if (FAILED(hr))
{
wprintf(L"g_pScheduler->CreateTaskId failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pJob->OpenTask(pTaskId, &pTask);
if (FAILED(hr))
{
wprintf(L"pJob->OpenTask failed with 0x%x.\n", hr);
goto cleanup;
}
pTaskId->Release();
pTaskId = NULL;
hr = pTask->put_StartValue(3);
if (FAILED(hr))
{
wprintf(L"pTask->put_StartValue failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pTask->put_StdOutFilePath(_bstr_t(L"<FULLPATHGOESHERE>\\echo_inst*.txt"));
if (FAILED(hr))
{
wprintf(L"pTask->put_StdOutFilePath failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pTask->Commit();
if (FAILED(hr))
{
wprintf(L"pTask->Commit failed with 0x%x.\n", hr);
goto cleanup;
}
pTask->Release();
pTask = NULL;
// Add a new task to the job.
hr = pJob->CreateTask(&pTask);
if (FAILED(hr))
{
wprintf(L"pJob->CreateTask failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pTask->put_CommandLine(_bstr_t(L"echo \"new task\""));
if (FAILED(hr))
{
wprintf(L"pTask->put_CommandLine failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pTask->put_StdOutFilePath(_bstr_t(L"<FULLPATHGOESHERE>\\new.txt"));
if (FAILED(hr))
{
wprintf(L"pTask->put_StdOutFilePath failed with 0x%x.\n", hr);
goto cleanup;
}
hr = pJob->AddTask(pTask);
if (FAILED(hr))
{
wprintf(L"pJob->AddTask failed with 0x%x.\n", hr);
goto cleanup;
}
cleanup:
if (pJob)
pJob->Release();
if (pTask)
pTask->Release();
if (pTaskId)
pTaskId->Release();
}