The following comments are a response to the call for public comment as seen at
https://www.ogc.org/requests/ogc-api-processes-standard-version-2-public-comment/
Me and @francbartoli have conducted a review of the proposed documents in light of our on-going work with pygeoapi-prefect, which is an open source project that provides an alternative process manager for pygeoapi.
The comments that follow relate to the whole of part1 version2 and part 2 - I hope this is an appropriate way to deliver them.
These focus mainly on things that we think could be improved or need additional discussion in the reviewed documents. In case the language is not clear, please note that all of these express only our opinions and are solely meant to be interpreted in light of trying to provide constructive criticism - we are not native english speakers, so please excuse the tone if it may seem somehow inadequate sometimes 😉 .
OGC API - Processes - Part 1: Core
The reviewed document is available online at:
https://docs.ogc.org/DRAFTS/18-062r3.html
2. Conformance
It seems unfortunate that the conformance class named ‘OGC Process Description’ is not mandatory, as this would seem like a very relevant thing to standardize.
The introduction of Conformance classes for specifying collections as inputs and outputs is a welcome addition to the standard.
Allowing process execution to be invoked via HTTP GET, as described in the conformance class ‘KVP-Encoded Execute’ is contrary to what HTTP verbs represent and also seems like a compromise that a standards body should not make.
4.1.12 Process (Terms and definitions)
It is relevant that processes without inputs and without outputs are specifically mentioned as being possible - these open up some additional use cases for the standard.
7.12 Operation (execute a process)
The execution of a process being triggered by POSTing a document with execution details to the path /processes/{processID}/execution is not inline with the resource-oriented nature of the REST paradigm - execution is not a resource, it is an action that has a process as its subject and which results in the generation of a job.
The conceptual model presented in the standard is based on two main resource types: Process and Job. A job may be a materialization of a parent process, created as the result of executing the project - but the REST paradigm does not deal with how resources are created, it just deals with how their representations are transmitted between two parties.
In a REST-based API, rather than asking the server to execute a process, a client would instead ask it to create a new job resource. Creating a new job resource would require POSTing a job representation to an appropriate path and then waiting for the server to provide a response on whether it could create the mentioned job or not.
As such, a typical REST-based API would define an operation based on POSTing a document with a job description to /processes/{processID}/jobs/, or maybe a path like /jobs instead.
The standard mentions that:
Depending on the description of the process and the negotiated execution mode, process execution may result in the creation of a job resource.
In other words, this means a server is not required to create a job resource. This seems contrary to the conceptual model used by the standard itself, whereby a Job is described as being the materialization of a Process execution (as per section 4.1.5). Perhaps a better framing would say that process execution may result in a job being persisted - i.e a job is always created, but it may or may not be stored as a persistent resource.
This seems designed to cater for the use case of servers that only respond synchronously and that do not store any state regarding execution requests. Such a server would receive a request, create a latent job which results in the generation of some output and immediately return it to the client as a response. This use case is likely to be the main justification for the existence of the API path /processes/{processID}/execution. However, the fact that the server may not persist jobs is not a reason for it not providing a /process/{processID}/jobs path where clients can POST job descriptions for being accepted. A server is perfectly able to provide API paths that only accept POSTing.
7.12.2.2 Execution mode
The standard mentions that a process may be executed synchronously or asynchronously and goes on to mention that the mode used by the server is a function of the job control options specified in the process description and of the presence of a Prefer HTTP header in the execution request.
However, because there is no officially mandated schema for the process description (only a recommendation that servers should consider supporting the OGC process description), it is possible and valid that a server has processes whose description does not define any job control options. Such a scenario is not discussed in the document though.
The standard mentions that sync execution mode is the default mode when the client does not state any preference.
The standard then implies that the server is expected to always service the execution request regardless of being able to satisfy the requested operation mode. It even specifies that the server is free to disregard the client’s requested operation mode even if it supports such mode, and simply perform execution using whatever mode it finds more appropriate. The standard does recommend that servers honor client’s requested mode, if serviceable, but does not mandate it though.
This means that:
- If a client requests async execution of a process and the server does not support async mode, then the server must execute in sync mode, contrary to what was requested;
- If a client requests sync execution and the server supports both sync and async, the server may respond with async execution, contrary to what was requested.
This level of flexibility is likely to force prospective clients to be overly complex, as they will need to accommodate for all possible execution cases if wanting to be truly interoperable.
A simpler design where the server refuses to service execution requests if it cannot meet the client expectations and otherwise will always honor serviceable requests would likely lead to simpler implementation in clients. This would mean that:
- The server responds with an error message if it cannot employ the requested execution mode;
- If requested execution mode is supported and the server accepts the request, then it must use the requested mode.
7.12.2.3.2. Input values
In ‘Example 3 - Qualified value examples’ the name of the process input is not consistent - in the process description it is named ‘geometryInput’ but in the execute request the name is ‘geometryInputs’.
The text below Requirement 25 mentions default and enum properties that are not visible in listing 17 because they are part of the ‘bbox-def-crs.yaml’ schema, which is not shown. This makes the text (and Permission 7) confusing.
There is very little mention of non-inline inputs in the document, these are just mentioned in item B of Requirement 26.
7.12.2.4. Process outputs
The document mentions that a client needs to be prepared to receive outputs as inline values or as a reference, regardless of the value sent by the client in the HTTP Prefer header - this note seems out of place in this section of the document. It would make more sense if it came next to the discussion of the Prefer header. Additionally, a more predictable behavior would make it easier to implement clients - the document could mandate that the server either honors the client’s preference or raises an error if it cannot.
7.12.4.2. Response requesting a single processing output (maxOccurs=1)
The contents of this section focus on the synchronous execution mode, yet NOTE 2 mentions that clients can use an HTTP HEAD to determine the size of a response. This note seems inappropriately placed, as on a synchronous request the processing is done in-band and the response is thus sent immediately following the client’s initial POST request. Therefore it is not possible to perform a HEAD request in the context of the same processing job when discussing synchronous execution.
‘Table 9 - Execute responses based on number of requested outputs, request HTTP headers and the size of output values’ specifies a return status code of 200 for successful sync execution requests. However, the example code shown after Permission 8 discusses how a server is allowed to respond with HTTP 303 in order to have the client redirect to another page upon successful execution. This seems to contradict Table 9.
Recommendations 18, 19, 21 and 22 mention how, when a sync request is serviced and the negotiated return preference is minimal, the server is allowed to decide how to transmit an execution result based on it being considered small or not and how this may result in the output being transmitted inline or by reference. In our opinion it would be better if the document committed to an explicit behavior instead of leaving it up for interpretation - this would make it easier to implement clients.
Requirement 32, item 4 writes ‘Optionally, the negotiated profile is …’ - If this item is optional, then it should not be part of the text, as it does not contribute to the fulfillment of Req 32 then.
7.12.4.8. Response for asynchronous process execution
Requirements 37 and 38 mandate that a server must own a job results’ output URLs on paths like ‘/jobs/{jobID}/results/{outputID}’ and ‘/jobs/{jobID}/results/{outputID}/{N}’ but makes no comment on what is the value added by this imposition. In our opinion this is overly restrictive and provides no real advantage - we could be proved wrong, but the document provides no context for this decision.
Given the fact that recommendation 25 already mentions a server needing to include links to job results (when available), then it seems that also specifying a server-controlled URL template for results would not be necessary. We recognize that some servers may want to enforce this as a policy, but think it should not be mandated by the standard.
A common and valuable use case that this seems to ignore is that of a server placing process output results on a cloud storage platform. As noted above, the document does have a brief mention of the possibility to use an HTTP 303 status in order to have clients redirect elsewhere but this is relegated to a simple example.
7.13. Retrieve status information about a job
Perhaps a minor nit, but the statusInfo.yaml schema would likely be better named as job.yaml, or with some other name that has the word job in it - as this is in fact a description of a job resource's schema.
The document does not clarify the usefulness of the processEntityType and profileEntityType properties. We can only guess that these exist in order to satisfy requirements of other documents. It would be good if the document provided a bit more context.
All of the temporal properties (created, started, finished, updated) are optional and NOTE4 also mentions how a duration may be calculated from these - this seems to be relevant mostly for the optional Job List requirements class, so it seems like these should be part of said requirements class instead.
8.3. Collection Output
The ability to create a new collection as the output of process execution seems like a valuable feature. However, it seems inconsistent to have the response parameter be part of the request’s query part instead of being an additional parameter in the request body (i.e. specifying it as an extension of execute.yaml schema).
8.4. Local Filtering
All local filters are grouped together in a single requirements class, but it is unclear which of them must be supported as they are all optional. It is also unclear what should be the outcome of a filtering request where the requested filters are not implemented. This needs to be clarified in order to better understand how a server can achieve compliance with the requirement class.
9.3.2. Data classes
It is not clear how an execution input is to be tagged with a data class. There does not seem to be any provision for this in the execution-related schemas.
9.3.7. Execution unit requirements
It is unclear why a process would need to inform clients of its internal execution environment. Given that the process can already describe whether it accepts inputs to be provided by value or by reference (via the valuePassing parameter) it seems that also providing information about whether the process environment has remote access and how the input is to be staged for execution is exposing server implementation details that a client would not need to know about.
12.2.2. Parameter type (job list)
It is unclear what other types a job could have besides ‘process’ and it is unclear why other job types would be shown on a process jobs list. Perhaps this means that other OGC API standards are also creating jobs and that this list would somehow show all of them? If that is the case, then some additional context is likely needed in the document text.
14. Requirements class “Dismiss”
The prescribed HTTP DELETE operation does not seem to be idempotent, as it is possible to call it a first time to cancel a running job and set its status to dismissed and then call it a second time to have the job be removed.
15. Requirements class “kvp-encoded execute”
Triggering process execution via HTTP GET is not inline with how HTTP verbs are usually meant to operate. This seems to be an anti-pattern and the document does not make a compelling case for why it would be accepted in the standard. It is our opinion that this requirements class should not be part of OGC API - Processes at all.
OGC API - Processes - Part 2: Deploy, Replace, Undeploy
The reviewed document is available online at:
https://docs.ogc.org/DRAFTS/20-044.html
6.6.4 Response (Deploying a new process to the API)
By accepting a response with a status of either 201 (Created) or 202 (Accepted), the document is implicitly committing to allowing both synchronous and asynchronous process creation workflows.
A 201 response means that when the client receives the response, the resource already exists. A 202 response however, means that when the client receives the response, the resource is not guaranteed to exist yet, but will in the future (if all goes well).
Requirement 9 goes on to specify the body of the response but it assumes the new process resource has been created already - this is inconsistent with the previously stated possibility of the server having not created the resource yet.
6.7. Replacing an existing process
In our opinion this should be part of a different requirements class.
Updating a previously existing process is not something that all servers may want to support, as having a process be updated can be a surprise to its users. Processes are computation units and having their internal logic modified is likely to produce different outcomes given the same set of inputs.
The document opts out of discussing process versioning and simply allows a process to be replaced. We think this is a missed opportunity, as it would be beneficial to advocate for immutable processes, which can only be created or deleted, in which case, reusing the same process id would be disallowed.
The response is also allowed to have either status 200 (OK), 204 (No Content), 201 (Created) or 202 (Accepted). The document then states (Requirement 17) that a response of either 200, 201 or 202 is required to contain the process summary in its response body - this is the same inconsistency as noted above, whereby a response status code of 202 means that the resource has not been created yet, and therefore the server does not yet have a representation to return.
7.3. processDescription property
By making the processDescription property be optional and letting it be inferred by the information contained in the execution unit, the document is forcing servers to implement additional logic to understand how a process’ inputs and outputs must be exposed - this seems needlessly complex. It would be reasonable to ask that a process description is required to contain information about how it should be called.
7.4. executionUnit Property
It seems odd that this property can be either an executionUnitBase or an array of executionUnitBase - it is not clear what would the array form mean.
The type property being an enum with values docker and oci is questionable, since docker images are oci-compliant. It seems like this property does not need to exist then.
8.4. Property deployment (Requirements class “Docker”)
Where a process gets deployed by the server should not be a concern of the client - this is an implementation detail. The document does not make the case for why providing this much control over the server’s internal execution environment would be beneficial.
8.6 Property bindings
This section needs some examples that show how the various parameters of input and output bindings can be used.
The following comments are a response to the call for public comment as seen at
https://www.ogc.org/requests/ogc-api-processes-standard-version-2-public-comment/
Me and @francbartoli have conducted a review of the proposed documents in light of our on-going work with pygeoapi-prefect, which is an open source project that provides an alternative process manager for pygeoapi.
The comments that follow relate to the whole of part1 version2 and part 2 - I hope this is an appropriate way to deliver them.
These focus mainly on things that we think could be improved or need additional discussion in the reviewed documents. In case the language is not clear, please note that all of these express only our opinions and are solely meant to be interpreted in light of trying to provide constructive criticism - we are not native english speakers, so please excuse the tone if it may seem somehow inadequate sometimes 😉 .
OGC API - Processes - Part 1: Core
The reviewed document is available online at:
https://docs.ogc.org/DRAFTS/18-062r3.html
2. Conformance
It seems unfortunate that the conformance class named ‘OGC Process Description’ is not mandatory, as this would seem like a very relevant thing to standardize.
The introduction of Conformance classes for specifying collections as inputs and outputs is a welcome addition to the standard.
Allowing process execution to be invoked via HTTP GET, as described in the conformance class ‘KVP-Encoded Execute’ is contrary to what HTTP verbs represent and also seems like a compromise that a standards body should not make.
4.1.12 Process (Terms and definitions)
It is relevant that processes without inputs and without outputs are specifically mentioned as being possible - these open up some additional use cases for the standard.
7.12 Operation (execute a process)
The execution of a process being triggered by POSTing a document with execution details to the path
/processes/{processID}/executionis not inline with the resource-oriented nature of the REST paradigm - execution is not a resource, it is an action that has a process as its subject and which results in the generation of a job.The conceptual model presented in the standard is based on two main resource types:
ProcessandJob. A job may be a materialization of a parent process, created as the result of executing the project - but the REST paradigm does not deal with how resources are created, it just deals with how their representations are transmitted between two parties.In a REST-based API, rather than asking the server to execute a process, a client would instead ask it to create a new job resource. Creating a new job resource would require POSTing a job representation to an appropriate path and then waiting for the server to provide a response on whether it could create the mentioned job or not.
As such, a typical REST-based API would define an operation based on POSTing a document with a job description to
/processes/{processID}/jobs/, or maybe a path like/jobsinstead.The standard mentions that:
In other words, this means a server is not required to create a job resource. This seems contrary to the conceptual model used by the standard itself, whereby a Job is described as being the materialization of a Process execution (as per section 4.1.5). Perhaps a better framing would say that process execution may result in a job being persisted - i.e a job is always created, but it may or may not be stored as a persistent resource.
This seems designed to cater for the use case of servers that only respond synchronously and that do not store any state regarding execution requests. Such a server would receive a request, create a latent job which results in the generation of some output and immediately return it to the client as a response. This use case is likely to be the main justification for the existence of the API path
/processes/{processID}/execution. However, the fact that the server may not persist jobs is not a reason for it not providing a/process/{processID}/jobspath where clients can POST job descriptions for being accepted. A server is perfectly able to provide API paths that only accept POSTing.7.12.2.2 Execution mode
The standard mentions that a process may be executed synchronously or asynchronously and goes on to mention that the mode used by the server is a function of the job control options specified in the process description and of the presence of a
PreferHTTP header in the execution request.However, because there is no officially mandated schema for the process description (only a recommendation that servers should consider supporting the OGC process description), it is possible and valid that a server has processes whose description does not define any job control options. Such a scenario is not discussed in the document though.
The standard mentions that sync execution mode is the default mode when the client does not state any preference.
The standard then implies that the server is expected to always service the execution request regardless of being able to satisfy the requested operation mode. It even specifies that the server is free to disregard the client’s requested operation mode even if it supports such mode, and simply perform execution using whatever mode it finds more appropriate. The standard does recommend that servers honor client’s requested mode, if serviceable, but does not mandate it though.
This means that:
This level of flexibility is likely to force prospective clients to be overly complex, as they will need to accommodate for all possible execution cases if wanting to be truly interoperable.
A simpler design where the server refuses to service execution requests if it cannot meet the client expectations and otherwise will always honor serviceable requests would likely lead to simpler implementation in clients. This would mean that:
7.12.2.3.2. Input values
In ‘Example 3 - Qualified value examples’ the name of the process input is not consistent - in the process description it is named ‘geometryInput’ but in the execute request the name is ‘geometryInputs’.
The text below Requirement 25 mentions
defaultandenumproperties that are not visible in listing 17 because they are part of the ‘bbox-def-crs.yaml’ schema, which is not shown. This makes the text (and Permission 7) confusing.There is very little mention of non-inline inputs in the document, these are just mentioned in item B of Requirement 26.
7.12.2.4. Process outputs
The document mentions that a client needs to be prepared to receive outputs as inline values or as a reference, regardless of the value sent by the client in the HTTP
Preferheader - this note seems out of place in this section of the document. It would make more sense if it came next to the discussion of thePreferheader. Additionally, a more predictable behavior would make it easier to implement clients - the document could mandate that the server either honors the client’s preference or raises an error if it cannot.7.12.4.2. Response requesting a single processing output (maxOccurs=1)
The contents of this section focus on the synchronous execution mode, yet NOTE 2 mentions that clients can use an HTTP HEAD to determine the size of a response. This note seems inappropriately placed, as on a synchronous request the processing is done in-band and the response is thus sent immediately following the client’s initial POST request. Therefore it is not possible to perform a HEAD request in the context of the same processing job when discussing synchronous execution.
‘Table 9 - Execute responses based on number of requested outputs, request HTTP headers and the size of output values’ specifies a return status code of 200 for successful sync execution requests. However, the example code shown after Permission 8 discusses how a server is allowed to respond with HTTP 303 in order to have the client redirect to another page upon successful execution. This seems to contradict Table 9.
Recommendations 18, 19, 21 and 22 mention how, when a sync request is serviced and the negotiated return preference is
minimal, the server is allowed to decide how to transmit an execution result based on it being considered small or not and how this may result in the output being transmitted inline or by reference. In our opinion it would be better if the document committed to an explicit behavior instead of leaving it up for interpretation - this would make it easier to implement clients.Requirement 32, item 4 writes ‘Optionally, the negotiated profile is …’ - If this item is optional, then it should not be part of the text, as it does not contribute to the fulfillment of Req 32 then.
7.12.4.8. Response for asynchronous process execution
Requirements 37 and 38 mandate that a server must own a job results’ output URLs on paths like
‘/jobs/{jobID}/results/{outputID}’and‘/jobs/{jobID}/results/{outputID}/{N}’but makes no comment on what is the value added by this imposition. In our opinion this is overly restrictive and provides no real advantage - we could be proved wrong, but the document provides no context for this decision.Given the fact that recommendation 25 already mentions a server needing to include links to job results (when available), then it seems that also specifying a server-controlled URL template for results would not be necessary. We recognize that some servers may want to enforce this as a policy, but think it should not be mandated by the standard.
A common and valuable use case that this seems to ignore is that of a server placing process output results on a cloud storage platform. As noted above, the document does have a brief mention of the possibility to use an HTTP 303 status in order to have clients redirect elsewhere but this is relegated to a simple example.
7.13. Retrieve status information about a job
Perhaps a minor nit, but the
statusInfo.yamlschema would likely be better named asjob.yaml, or with some other name that has the word job in it - as this is in fact a description of a job resource's schema.The document does not clarify the usefulness of the
processEntityTypeandprofileEntityTypeproperties. We can only guess that these exist in order to satisfy requirements of other documents. It would be good if the document provided a bit more context.All of the temporal properties (
created,started,finished,updated) are optional and NOTE4 also mentions how adurationmay be calculated from these - this seems to be relevant mostly for the optional Job List requirements class, so it seems like these should be part of said requirements class instead.8.3. Collection Output
The ability to create a new collection as the output of process execution seems like a valuable feature. However, it seems inconsistent to have the
responseparameter be part of the request’s query part instead of being an additional parameter in the request body (i.e. specifying it as an extension ofexecute.yamlschema).8.4. Local Filtering
All local filters are grouped together in a single requirements class, but it is unclear which of them must be supported as they are all optional. It is also unclear what should be the outcome of a filtering request where the requested filters are not implemented. This needs to be clarified in order to better understand how a server can achieve compliance with the requirement class.
9.3.2. Data classes
It is not clear how an execution input is to be tagged with a data class. There does not seem to be any provision for this in the execution-related schemas.
9.3.7. Execution unit requirements
It is unclear why a process would need to inform clients of its internal execution environment. Given that the process can already describe whether it accepts inputs to be provided by value or by reference (via the
valuePassingparameter) it seems that also providing information about whether the process environment has remote access and how the input is to be staged for execution is exposing server implementation details that a client would not need to know about.12.2.2. Parameter type (job list)
It is unclear what other types a job could have besides
‘process’and it is unclear why other job types would be shown on a process jobs list. Perhaps this means that other OGC API standards are also creating jobs and that this list would somehow show all of them? If that is the case, then some additional context is likely needed in the document text.14. Requirements class “Dismiss”
The prescribed HTTP DELETE operation does not seem to be idempotent, as it is possible to call it a first time to cancel a running job and set its status to dismissed and then call it a second time to have the job be removed.
15. Requirements class “kvp-encoded execute”
Triggering process execution via HTTP GET is not inline with how HTTP verbs are usually meant to operate. This seems to be an anti-pattern and the document does not make a compelling case for why it would be accepted in the standard. It is our opinion that this requirements class should not be part of OGC API - Processes at all.
OGC API - Processes - Part 2: Deploy, Replace, Undeploy
The reviewed document is available online at:
https://docs.ogc.org/DRAFTS/20-044.html
6.6.4 Response (Deploying a new process to the API)
By accepting a response with a status of either
201 (Created)or202 (Accepted), the document is implicitly committing to allowing both synchronous and asynchronous process creation workflows.A 201 response means that when the client receives the response, the resource already exists. A 202 response however, means that when the client receives the response, the resource is not guaranteed to exist yet, but will in the future (if all goes well).
Requirement 9 goes on to specify the body of the response but it assumes the new process resource has been created already - this is inconsistent with the previously stated possibility of the server having not created the resource yet.
6.7. Replacing an existing process
In our opinion this should be part of a different requirements class.
Updating a previously existing process is not something that all servers may want to support, as having a process be updated can be a surprise to its users. Processes are computation units and having their internal logic modified is likely to produce different outcomes given the same set of inputs.
The document opts out of discussing process versioning and simply allows a process to be replaced. We think this is a missed opportunity, as it would be beneficial to advocate for immutable processes, which can only be created or deleted, in which case, reusing the same process id would be disallowed.
The response is also allowed to have either status
200 (OK),204 (No Content),201 (Created)or202 (Accepted). The document then states (Requirement 17) that a response of either 200, 201 or 202 is required to contain the process summary in its response body - this is the same inconsistency as noted above, whereby a response status code of 202 means that the resource has not been created yet, and therefore the server does not yet have a representation to return.7.3. processDescription property
By making the
processDescriptionproperty be optional and letting it be inferred by the information contained in the execution unit, the document is forcing servers to implement additional logic to understand how a process’ inputs and outputs must be exposed - this seems needlessly complex. It would be reasonable to ask that a process description is required to contain information about how it should be called.7.4. executionUnit Property
It seems odd that this property can be either an
executionUnitBaseor an array of executionUnitBase - it is not clear what would the array form mean.The
typeproperty being an enum with valuesdockerandociis questionable, since docker images are oci-compliant. It seems like this property does not need to exist then.8.4. Property deployment (Requirements class “Docker”)
Where a process gets deployed by the server should not be a concern of the client - this is an implementation detail. The document does not make the case for why providing this much control over the server’s internal execution environment would be beneficial.
8.6 Property bindings
This section needs some examples that show how the various parameters of input and output bindings can be used.