robocorp-action-server
Serving Actions with the Action Server
The action server's main purpose is managing the lifecycle of actions in an action package.
There are a number of customizations available which make it flexible to work and manage which actions should be executed. The guide shows a few of these use-cases below.
Serving actions from the current directory
The simplest case is just starting the action server at a given folder with:
In this case, the action server will search recursively for all the Actions
marked as @action
in files named as *action*.py
and then it'll start
serving such actions. Any @action
which
is no longer found from a previous run will be disabled.
All the settings and data related to this run will be stored a folder
located in a directory in ~/robocorp/.action_server
(or
%LOCALAPPDATA%/robocorp/.action_server
in windows) which is automatically
computed based on the current directory location.
It's possible to customize the directory by using the --datadir
flag.
Example:
Serving actions from multiple directories
In this case, instead of just using action-server start
, one needs to
import the actions saving the settings to a given datadir and then
start the server pointing to that datadir asking the action-server
not to synchronize the actions again when starting.
Example:
package.yaml
Note: introduced in the Action Server version: 0.0.21
The package.yaml
file is the base file which defines everything related to the
actions available in the action package.
Note: previous versions of the action server used a
conda.yaml
oraction-server.yaml
, which are not directly compatible topackage.yaml
(so, they can't be just renamed directly and some changes are expected in how to define the environment).
Running:
action-server package update
can be used to automatically upgrade a package in an older version to the new expected format.
An example package.yaml
would be something as:
Running actions
The action server has a few command line parameters when it's started which define how actions will be run and whether actions must be run isolated from other actions.
Reuse process
The most important flag here is --reuse-process
. When this flag is activated,
the action server will invoke the same @action
multiple times, utilizing
the same process where the @action
was previously executed.
If --reuse-process
is not passed, a new process will be created to run the action
and each new invocation will run in a completely clean environment.
Notes on process reusal:
It's usually faster to run with --reuse-process
as after the action runs once, all modules are already imported and the global
state is reused (so, subsequent calls to the action will have the same
global variables in place).
Keep in mind that some environment variables may be changed across calls
to an @action
(for instance to update where the results should be written).
In such cases, those should not be stored in a global variable.
Process pool
The action server can execute processes using a process pool (by providing the
--min-processes
and --max-processes
command line arguments).
In general, if --reuse-process
is set and more than one process is available,
the action server may redirect a new request to any of the existing processes
(as long as the environment is compatible), so, for instance, if there are
three different @action
s in the same package, the action server can forward
a request to any of the existing processes.
This implies that unless --min-processes
and --max-processes
are both
set to 1
and --reuse-process
is enabled, global state that needs to
persist for handling session information should be stored externally
(e.g., in a sqlite database or another external service/location for
storing user-session information).
Whitelisting actions to be run
There are 2 situations where one can whitelist the actions which should be used, at import and at server start time.
This can be specified in the --whitelist
command line parameter.
Whitelist argument spec
-
The format of the whitelist is flexible so that it accepts the format accepted by fnmatch.
-
The package name can potentially be matched too (if
/
is added the package name is matched, otherwise just the action name is matched). -
It's possible to specify multiple actions by separating them with a comma.
-
-
and_
may be used interchangeably.
Examples
--whitelist "action-1,action_2"
--whitelist "package1/action*1,package2/action*2"
--whitelist "*foo/sheet,*bar/sheet"
--whitelist "*foo/*"
Importing actions
When actions are imported, it's possible to whitelist which actions should actually be imported.
Example:
Serving actions
When actions are served, it's possible to whitelist which actions should actually be available to run.
Example:
Dealing with custom data models
Starting with robocorp-actions 0.0.8
and Action Server 0.0.28
, custom
pydantic models may be used to define a schema containing complex objects as
the input/output of a an @action
.
-- previous versions supported just str
, int
, float
, bool
.
Example
To define a custom data model, pydantic classes must be used to define the shape of the data.
Below is an example which defines an @action
with a custom input and output:
Note
Note: pydantic
is not a hard dependency of robocorp-actions
and must
be included as a custom dependency in projects that require custom data models.
Exposing a local action server
To expose a local running action server for public access, it's possible
to use action-server start --expose
.
By doing so, the action-server
will automatically connect to a
server and you'll get a public reference to it on the robocorp.link
domain
(for instance https://twently-cuddly-dinosaurs.robocorp.link
).
Note: if the server is stopped and restarted, it'll ask to reconnect to
the same server afterwards as url/access secret is stored in the datadir.
If you say No
, a new url/access secret will be generated and the old
one will be lost, so, it may be interesting to backup the expose_session.json
from your datadir if you plan to keep using the same url later on (the datadir is
printed in the console whenever you start your action server).
Authentication
Currently the Action Server supports a basic authentication scheme using an API key with "Bearer" authentication.
To set it up, it's possible to pass --api-key=<api key>
in the
to the action-server start
.
Note that if --api-key
is not passed along with --expose
, an
api key will be automatically generated and saved in your datadir/.api_key
.
Consider backing it up if you want to keep using the same api key.
Calling server with API key enabled
If the --api-key
was passed (or if this was an exposed server which
had the api automatcially generated), to call any method from its API,
a header such as:
"Authorization": "Bearer <api-key>"
must be passed in all requests (excluding /openapi.json
).
Building Action Package zip to distribute:
The action server can be used to serve Action Packages, which is a project
containing multiple defined actions (specified by using the @action
decorator
in .py
files), with the related metadata (package.yaml
).
To share these Action Packages the action server has the following command:
action-server package build
This will build a .zip
containing the files from the Action Package. By
default all the files from the Action Package directory are recursively added
to the .zip
, and it's possible to customize files which shouldn't be added
to the action server by specifying them in the package.yaml
in the
packaging/exclude
section (entries are based on the
glob format.
Example:
Note: using action-server package build
with the package.yaml
above will
create a .zip
named: crm-automation-0.2.3.zip
in the current directory.
Extracting zip with Action Package:
To extract the Action Package from the crm-automation-0.2.3.zip
previously created, it's possible to use:
action-server package extract crm-automation-0.2.3.zip --output-dir=v023
Note: if --output-dir
is not given, the current directory will be used.
Note: --override
can be given to override the contents of the directory
without asking for confirmation.
Collecting metadata from an Action Package:
To collect metadata from a given Action Package (which must be extracted in the filesystem), it's possible to run:
action-server package metadata
By doing so it'll write to stdout
the metadata from the Action Package
(in version 0.2.0
this only includes one openapi.json
entry with the
openapi.json
contents, but it's expected that this will have more information
in the future).
Note: logging may still be written to stderr
and if the process returns with
a non-zero value the stderr
should have information on what failed.
From action-server 0.3.0
onwards, data on the expected secrets is also available
in the returned metadata.
The full structure given in the output is something as:
Secrets
Important: Requires robocorp-actions 0.2.0
onwards to work.
Important: On robocorp-actions 0.2.1
the auth-tag
is accepted (on 0.2.0
an empty string would always be used as the auth-tag).
Receiving a Secret
To receive secrets using actions, it's possible to add a parameter with a 'Secret' type so that it's automatically received by the action.
i.e.:
Passing Secrets (Development mode inside of VSCode)
In development mode a secret can be passed by using the input.json
(which
is automatically created when an action is about to be run).
i.e.: in the case above a my_secret
entry in the json will be automatically
used as the my_secret.value
.
Example input.json
:
Passing Secrets (Production mode)
In production secrets should be passed in the X-Action-Context
header.
The expected format of that header is a base64(JSON.stringify(content)) where the content is a json object such as:
In python code it'd be something as:
Note: the X-Action-Context
header can also be passed encrypted with a
key shared with the action server in the environment variables.
In that case the X-Action-Context
header contents should be something as:
In python code it'd be something as:
The actual key
used in the encryption should be set in ACTION_SERVER_DECRYPT_KEYS
in the environment variables such that it's a json with the keys in base64.
In python code:
Note: all the keys will be checked in order and the caller may use any of the keys set to encrypt the data.