-
Notifications
You must be signed in to change notification settings - Fork 0
Work order
This document proposes a generic "Here is some work" document. It provides user agents with a clear way of identifying work, and what to do in order to complete the work, and what to do when work has completed. It is intended to be consumed by client components that have been programmed to perform specific tasks.
In the context of workflow systems, there is a need for specialized workers (software programs) that perform a narrow task, like building some code, booting a server or sending an invoice. In distributed workflow systems, these workers may be far apart, possibly under different jurisdictions, with no way of interacting. A worker needs to be able to decide if the work solely based on a single interaction with the server, and then perform the work. The media type application/vnd.mogsie.work-order+json
aims to provide a simple format that allows servers and agents to gain a shared understanding that here is work that needs to be done.
Using this media type it will be possible to construct machine agents (automotons) that, when they discover a application/vnd.mogsie.work-order+json
document which conforms to the agent's requirements, will be able to perform their (narrow) work, and report back when they're done.
Documents of this type are expected to be found in some sort of collection, such as a collection+json
or an atom+xml
, but that is outside the scope of this specification. Likewise the discovery of these collections is also outside the scope of this specification.
A simple work order may look like this:
{
"type": ".../build-some-code",
"input": {
"source" : "https://exmample.com/example.git",
"revision" : "463a7b891ab678ffa07bc",
"type": "nodejs"
},
"start": "/work-orders/31789abc/take",
"status": "http://status-server.example.com/203009179793/status",
"complete": "/work-orders/31789abc/completed",
"fail": "/work-orders/31789abc/failed"
}
There are two main parts to a work order:
- the input to the agent identifying the work to be done (
type
andinput
) - the hypermedia controls used to advance the state of the agent (the rest)
The type
and input
attributes are all the worker needs to have in order to determine if the work at all fits the agent. If an agent is good at sending e-mails, it shouldn't try to perform work that is clearly labelled that it has to do with stopping a server.
This attribute is REQUIRED. The type
attribute identifies the domain specific type of work that the work is about. Agents SHOULD use this information to figure out if they are supposed to even attempt carrying out the work shown. The type
attribute MUST be an absolute URI.
It is expected that a registry of types be maintained to increase interoperability between workers.
This OPTIONAL attribute contains arbitrary information that is needed to carry out the work; this is an open-ended JSON structure, which is specific to the domain of the worker.
The contents of the input
will vary wildly depending on the type
of work being described. For a work order describing the need to send a tweet the input
might need to state the message of the tweet. On the other hand, a work order describing that a certain sound should be played on the machine's internal speaker, probably has a URL for the sound.
It is expected that the registry for types of work includes a description of the requirements for the input for each type.
These controls identify other resources that govern the work itself. Each of these controls mean something very specific, and an agent should follow them when certain situations occur. Most of the controls are non-idempotent, and unsafe, POST . These "controllers" allow the agent to inform the server about the agent's progress and ultimately complete the work.
The presence of the start
control is RECOMMENDED. When this control is present, an agent MUST invoke it and await a successful response before work starts. This control is present in work items where the server has deemed it important that the same work isn't done on by two agents at the same time. The server in question might achieve this by only responding successfully once; only one agent would "get" the work item.
POST (something TBD)
...
{ "about" : "something about the agent perhaps, for logging purposes" }
If the response is not successful, the agent MUST NOT start working on the work, and disregard the item. In this case the agent should continue to find other work to do.
For 5xx server errors, the client may of course retry at a later time, as specified in HTTP. For 4xx errors, the client should respond as appropriate. In particular, a 409 CONFLICT typically indicates that the item is not available anymore, possibly because another agent has already started work. The agent SHOULD ignore the work order and continue finding other work orders.
If the response of invoking the start
control is a work order, then the agent should continue using that work order instead of the work order it started on. In particular, the response might contain additional hypermedia controls (such as status
or complete
) instead of providing them in the original document. This is useful if the server does not wish to disclose certain URLs, like the fail
or complete
controls before an agent has started working on it, and then only to the agent that is working on it.
The presence of the status
control is OPTIONAL. When this control is present, the agent MAY invoke it whenever it wants to report it's current progress about the work, or if it wants to know if the work should be cancelled. The Status resource is a Status document, typically a application/status+json
or application/status+xml
document. Clients that wish to report on progress SHOULD retrieve their preferred status document, make changes as appropriate, and PUT it back.
GET /...
Accept: application/status+json
{ "status" : { ...
Then, to update the status, modify the status and PUT it back.
PUT /...
Content-Type: application/status+json
{ "status" : {
"state" : "ok",
"progress" : "2/73",
"message" : "Checking out source code"
}
}
If the client is willing but unable to successfully report its status, it SHOULD NOT interrupt the actual work being performed, but continue to monitor the status document for cancellation requests (see below).
See cancel
, below, to see the role of the status documents when it comes to server-initiated cancellation of work.
For long running work (e.g. several minutes) the agent SHOULD either retrieve or report progress every few minutes to ensure that the origin server doesn't think that the agent has died.
The complete
control is RECOMMENDED. When the complete
control is present, the agent MUST invoke it when work has been completed, with the POST method, optionally passing along with it the results of the work, if applicable. The request entity SHOULD have the content type application/x-www-form-urlencoded
, and SHOULD have the name/value pairs as outlined in the work item.
POST ...
Content-Type: application/x-www-form-urlencoded
The format of the data passed when invoking the complete
control is governed by the type
of work. It is expected that the registry that describes the types of work will include information about the desired response (their names and values).
A successful response indicates that the result of the work has been handed off, and the agent can continue looking for more work.
TBD: If you POST to /.../complete and get a 200 OK, isn't the agent really obliged (per follow-your-nose) to process the response to continue to the next state? Is it cheating to say that the agent should now "look for more work"?
The presence of the cancel
control is OPTIONAL. Cancellation is the process which starts when the server decides that it no longer is interested in the completion of work. Perhaps it had two workers doing the same work, and one completed, now it can say to the other worker to stop.
Note: If the agent no longer wants to continue, use the
fail
control instead.
Cancellation is something that happens in two phases. Phase one happens as a response to a GET of the status
hypermedia control. So to start things off, the agent needs to be requesting status updates. The response from the status should be a Status document. The Status document may indicate that the server no longer wants the work to continue, by setting the =state= to =cancelled=:
GET /...status...
200 OK
Content-Type: application/status+json
{ "status" : {
"state" : "cancelled",
...
}
}
If the Status document does indicate a cancellation, the Agent SHOULD stop working on whatever it is doing, in a graceful manner as possible. If the cancel
control is present SHOULD also invoke it.
The cancel
control informs the origin server that the agent successfully cancelled the work. If the agent is unable to cancel the work and the work completes inevitably, it should ignore the desire to cancel the work and complete
the work as normal.
The fail
control is OPTIONAL. When the fail
control is present, the agent SHOULD invoke it if it has started progress on a work item, but is unable to complete for whatever reason. This control informs that the work could not be completed, and the agent is no longer working on this work.
POST ...fail...
Content-Type: TBD
204 NO CONTENT
After successfully invoking the fail
control, the agent MAY continue with other work.
Here's an example of an exchange between a client that's able to perform some work, and a server that provides work orders. Here "WORK_ORDER" signifies the media type that describes one piece of work that needs to be done. The exchange is probably the simplest of exchanges.
Like a browser needs a home page, the agent starts out with the URL it was configured by its owner to start at. In our example it sees a Collection+JSON which contains perhaps three or four items, retrieves one of the vnd.WORK_ORDER
s, performs the work described in the work order, and finally reports back.
First, this agent receives a collection+json. Other agents might prefer other ways to discover work orders, e.g. atom feeds.
> GET /work-queue
< 200 OK Content-Type: collection+json
# the agent is now looking at a collection of (open) work orders.
The agent finds the work order (using meta data in the collection), and selects one to work on. Let's say /work-orders/su9fw
is one of the items:
# The robot follows that link:
> GET /work-orders/su9fw
< 200 OK Content-Type: application/vnd.mogsie.work-order+json
{
"type": "http://mogsie.com/static/work/compile-some-code/nuget",
"input":
{
"source" : "http://github.com/tavis-software/Link",
"test": "Tavis.Link.nuspec"
}
"start": "/work-orders/su9fw/take",
"status": "/work-orders/su9fw/status",
"complete": "/work-orders/su9fw/completed",
"fail": "/work-orders/su9fw/failed"
}
The agent is now looking at a work order which we'll assume the agent knows how to handle. In other words it knows how to compile some code according to nuget; it knows where to pull the source. The media type describes what to do with the start
, status
links, etc.
Since it contains the start
hypermedia control, it is obliged to invoke it
> POST /work-orders/su9fw/take
> Content-Type: TBD:
< 204 NO CONTENT
The agent can now start working. Downloading stuff, compiling, deploying code, whatever it's told to do, whatever it's good at.
Presumably the agent now performs the work described in the work order, and upon completion
# The agent has completed the work; in the work o
> POST /work-orders/su9fw/complete (some data)
< 204 NO CONTENT
With the successful handoff of the work, the agent can go back to the queue to grab another item.
The work order types MUST be URLs that SHOULD provide documentation about its intended use, inputs and outputs and other non-functional requirements.
Note: These work order types are more for horsing around since they don't really describe real work; They are here to illustrate the format of the registry.
Changes the color of some something
-
color
: (required string) string identifying a CSS color (hex, rgb, name of color etc) -
fade
(optional number between 0 and 100) duration used to fade to the color in question -
duration
(optional number between 0 and 100) length of time to keep that color
none
Plays a sound on a machine's speakers.
-
uri
: (required string) URI of the sound to play -
volume
(optional number between 0 and 100) volume to play the sound
none
Requests some textual input, typically from a user. Mainly for demonstration purposes, especially the color changing aspect of this "work".
-
title
: (required string) Text indicating tersely what the requested input will be used for. -
text
: (optional string) Additional information needed by the worker when getting textual input. -
color
: (optional string) A CSS color which should influence something colorful to the user.
-
text
: (required string) The new piece of text provided by the user.
Converts text to speech and plays on your speaker
-
text
: (required string) text to read -
volume
(optional number between 0 and 100) volume to play the sound
none
Generate a math problem
-
difficulty
: (required number 1 to 5 inclusive)
-
problem
: (required string) A human readable representation of the text problem. -
solution
: (required string) The expected answer.
Render an embed of the top result for the search term
-
search-term
: Term to search for
None
Send an email message to a given recipient.
-
recipient
: Recipient email address
None
Brew a coffee
-
drink-type
: Type of drink, e.g. 'mocha', 'coffee' -
size
: 'small', 'medium', or 'large' -
addons
: List of{'type': 'some type', 'amount': 'an amount'}
s
- 'coffee' a coffee string composed of the above
- e.g.
small mocha 2oz of half and half 1 cube of sugar
- e.g.
{
'type': 'restfest-coffee',
'input': {
'drink-type' : 'mocha',
'size': 'small',
'addons' : [
{ 'type' : 'half and half', 'amount' : '2oz' },
{ 'type' : 'sugar', 'amount' : '1 cube' }
]
}
}
Given a fragment of text, finds songs that match the contain the text as lyrics. Can then present the list and ideally let the user play the song.
-
lyric
: a fragment of song lyrics
None
Given a bit of text will translate from one language to another.
-
text
: the text to translate -
from
: the original source language. Use country code (i.e. 'en' for English) -
to
: the desired output language. Use country code (i.e. 'it' for Italian)
The translated text is the body of the POST on the complete
via a JSON string in the format:
{"translated": "some translated text"}
None
Given twitter handle, read the user's last tweet
-
handle
: the twitter user's username
Audio of the user's last tweet
None
Will call a number and speak a message
-
to
: The phone number to call (E.164 format. +14042908411) -
text
: The message to say
None
Receiving robot will speak the message out loud. If preferred_voice
is available on the robot handling the request, it will be used. If any voice of language preferred_lang
is available, one of those voices will be used. You cannot specify both a preferred voice and language, voice will take precedence and if the preferred voice is not available the default voice will be used.
-
text
: (required) The text to speak -
preferred_voice
: (optional) The preferred voice -
preferred_lang
: (optional) The preferred language
None
Given and input URL and a storage URL will download a video in any format and convert it to H.264/AAC (i.e. HTML5 video) and POST it to the storage URL. The storage URL can be any URL (pre-signed S3, etc.)
-
source_url
: The original video (https://dl.dropboxusercontent.com/s/9a62mgx3c6n7q0a/TeasingCat.MPG?token_hash=AAHzCQWBC4LSkuV-Vack03I92wDhuC_0rl2dVDYtbCPlJQ&dl=1) -
destination_url
: The converted HTML5 friendly video (http://requestb.in/1c80lli1)
None
Receiving robot will receive a list of legal moves, pick one and send that as the result of the work. It is expected that some robots actually use some form of higher intelligence to make a good choice.
-
board
: (required) The FEN string of the current board -
legal-moves
: (required) An array of strings, each containing a single move (eg. [ "a4", "nxb6" ]) -
transformations
: (optional) an object containing the transformation that would be applied for each legal move, to help clients with visualisations (see visualisations, below):{ "a3" : [ { "from": "a2", "to": "a3" } ], "a4" : [ { "from": "a2", "to": "a4" } ], "O-O-O" : [ { "from": "e1", "to": "c1" }, { "from": "a1", "to": "d1" } ], ... }
-
move
: (required) A string matching one of the strings fromlegal-moves
input.
Receiving robot will receive the FEN string for a board, and a list of transformations that should be applied to the board, and the new FEN string for the board. The "after" board is only useful for dumb visualisations
-
move
: The normal notation of the actual move e.g.hx1=Q+
for display only -
before
: (required) The FEN string of the board before the move -
after
: (required) The FEN string of the board after the move -
transform
: (required) An array containingfrom
,to
(a piece has moved) optionallypromote
(when a piece changes into a new type), or aremove
(when a piece is captured)[ { "from": "e2", "to": "f3", "promote": "q" }, { "remove": "f3" } ]
Transformations will be taken from chess.js' way of describing a move completely (actually returned from the move() operation) and will look something like this:
none, it is only expected to show a board somewhere.