Skip to content

Schedule a UC4 job

This operation starts a named UC4/Automic job. On the first call for a given UC4Client instance it also performs lazy, one-time initialization of the injected IHttpJsonClient with caller-identity information.

Field Value
Operation ID OP-UC4-02
Trigger Consumer calls await client.ScheduleJob(appname, jobname)
Inputs appname — the calling application's ID, sent as the Application-ID header. jobname — the UC4 job name, appended to the configured route.
Outputs Task<IHttpRequestResult>, the raw HTTP result; the caller must inspect IsSuccessful, StatusCode, and ErrorMessage.
Primary components UC4Client.ScheduleJob, UC4Client.Init
Entry point src/SAIF.NetCore.Clients.UC4/SAIF.NetCore.Clients.UC4/SAIF.NetCore.Clients.UC4/Services/UC4Client.cs

Steps

  1. If IsConfigured is false, run Init(appname); otherwise skip to step 3 (BR-UC4-06, BR-UC4-07).
  2. Not thread-safe (no lock); concurrent first calls may both run Init*.
  3. Init: call _httpJsonClient.SetClientInfo(ServiceUrl, ClientName, Environment.MachineName, appName), then set IsConfigured = true (BR-UC4-03, BR-UC4-04, BR-UC4-05).
  4. Delegates to SAIF.NetCore.HttpClients's HttpJsonClient.SetClientInfo(baseUrl, userName, machineName, applicationId): constructs ClientInfo(machineName, applicationId, userName) (throws ArgumentNullException if any argument is null) and sets _baseUri = new Uri(baseUrl).
  5. On failure: a null appname throws ArgumentNullException from ClientInfo; an empty or malformed ServiceUrl throws UriFormatException. In both cases IsConfigured stays false, so the next call retries Init.

Origin: Step 2 is implemented in Initialize client (SAIF.NetCore.HttpClients) and executed on behalf of this operation. 3. POST to $"{ScheduleJobEndpoint}{jobname}" with an empty JSON object ({}), with no job parameters (BR-UC4-03, BR-UC4-08, BR-UC4-09). - Delegates to HttpJsonClient.PostAsync(urlPart, body) → ExecuteAsync(urlPart, Method.POST, body, retries: 3): - ValidateInitialization, which throws ClientNotInitializedException if _clientInfo or _baseUri is null. - CreateClient, which sets the base URI and assigns client.Authenticator = _authenticator — the authenticator already held by the injected IHttpJsonClient instance, not a value UC4 itself sets or clears — plus the serializer and the timeout override (none for UC4). UC4 never calls SetNtlmAuthentication/SetBasicAuthentication or sets BearerToken, so the authenticator is whatever the host configured on the injected client: null if the host configured none, or a working authenticator (demonstrably capable of carrying credentials) if it did. - CreateRequest, which adds the JSON body and the headers Client-Name = machine name, Application-ID = appname, and Client-User = "SAIF.NetCore.Clients.UC4", plus Authorization only if BearerToken is set (never set by UC4), plus any custom Headers, which are then cleared. - Runs the request synchronously inside Task.Run; if the status is in RetryOnStatusCodes (default 401, 502, 503), sleeps RetryDelayInMs (default 1000 ms) and retries, up to 3 retries. These are standard HttpJsonClient defaults, changeable by a host that calls SetOptions, even though UC4 itself never calls SetOptions and never overrides them. - Builds HttpRequestResult (populates headers, and on failure populates ErrorMessage from errormessage/exceptionmessage/message JSON tokens or the raw content), stores it in RequestResult, and returns it.

Origin: The sub-steps above are implemented in HttpJsonClient (SAIF.NetCore.HttpClients) — see Execute request — and executed on behalf of this operation. - On failure: non-success HTTP status codes are not thrown; they are returned in IHttpRequestResult (IsSuccessful = false). Network failures surface as ErrorException or ErrorMessage on the result*. 4. Return the IHttpRequestResult to the caller unchanged (BR-UC4-09). - No interpretation of the response body; the UC4 run ID or any response payload is left for the caller to read with GetResult<T>() or Content.

Process flow

flowchart TD
    Start([Caller invokes ScheduleJob]) --> D1{IsConfigured?}
    D1 -->|No| Init["Init: SetClientInfo"]
    D1 -->|Yes| Post
    Init --> InitOk{Init succeeded?}
    InitOk -->|No| ErrInit([ArgumentNullException / UriFormatException])
    InitOk -->|Yes| Post["POST empty JSON object {} to route+jobname"]
    Post --> Retry{Status in 401/502/503<br>and retries remaining?}
    Retry -->|Yes| Post
    Retry -->|No| Result([Return IHttpRequestResult to caller])

Failure and edge-case behavior

  • A null appname on the first call: ArgumentNullException from ClientInfo; IsConfigured remains false, so the next call retries Init.
  • An externally-set IsConfigured = true before the first call: Init is skipped and the POST fails with ClientNotInitializedException unless the injected client was configured elsewhere.
  • A 502/503 response after the UC4 API has already accepted the job: the automatic retry can submit a duplicate job if the UC4 Core API's schedule endpoint is not idempotent, which is unknown**.
  • Any non-success response: returned as IHttpRequestResult.IsSuccessful = false, never thrown.

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts. Statements marked with ** could not be confirmed; treat as unknown until verified.

Sources

  • src/SAIF.NetCore.Clients.UC4/SAIF.NetCore.Clients.UC4/SAIF.NetCore.Clients.UC4/Services/UC4Client.cs
  • src/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/HttpJsonClient/HttpJsonClient.cs — declares SetClientInfo, PostAsync/ExecuteAsync, ValidateInitialization, CreateClient, and CreateRequest, the delegated behavior described in steps 2–3.
  • src/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/ClientInfo.cs — declares the constructor that throws ArgumentNullException for a null appname.
  • src/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/HttpClientOptions.cs — declares the RetryOnStatusCodes/RetryDelayInMs defaults applied in step 3.