Develop a service from your application
What is it for?¶
Applications may require server-side code execution that could not, or should not, be in the client. This might be useful for heavy computations or for tasks triggered after some events, typically after data is retrieved through konnectors or mobile/desktop sync, without the user being on the application.
In contrast to konnectors, services have the same permissions as the web application and are not intended to collect information from the outside. It is rather meant to asynchronously analyse data inside the cozy and emit some output once the task is done. However, they share the same mechanisms as the konnectors to describe how and when they should be executed: via our trigger system.
Example¶
You can find an example of an existing service in the cozy-banks app.
CozyClient instantiation¶
By using fromEnv
, you will be able to use the service in dev mode (via cozy-konnector-dev see Execution) or in production.
const client = CozyClient.fromEnv(process.env, { schema })
You may need to add this line to your service to use the fetch
for node:
global.fetch = require('node-fetch').default
Service declaration¶
The service must be declared in the app manifest. For example:
"services": { "onOperationCreate": { "type": "node", "file": "onOperationCreate.js", "trigger": "@event io.cozy.bank.operations:CREATED", "debounce": "3m" } }
Here is an explanation of the fields:
type
: describe the code type (onlynode
for now).file
: the single (packaged) file containing the code to execute as a service. It must be the relative path to the built service’s file, not the source one. Expl:/services/name-of-service/built-file.js
. Look at yourbuild
folder or build/watch console output to find it.trigger
: what triggers the service. It must follow the available triggers described in the jobs documentation. In this example, the trigger is a bank operation creation.debounce
(optionnal): The debounce parameter can be used to limit the number of jobs created in a burst. It delays the creation of the job on the first input by the given time argument, and if the trigger has its condition matched again during this period, it won’t create another job. Its syntax is the one understood by go’s time.ParseDuration. If this parameter is omitted, the service will be executed as soon as it can.
Build¶
The service must be packaged into a single file containing all the dependencies. An example of a webpack rule is available here. Note that target: 'node'
is important as the service is run as a Node.js process.
In this example, the services are built alongside your app using yarn watch
.
If you use cozy-script, you should use watch
and not start
to have the service built.
Stack¶
As the service is run on a dedicated process on the server side, a running stack is necessary. You can either use a stack installed with docker or directly from source.
Some configuration is required to execute the service and store the produced logs, to facilitate the development. The following instructions are for a stack installed from source, but you can adapt it for a docker installation: you have to download the default config file, modify it as described below and indicate its location through the docker command, as explained here.
In the following, we assume that your $HOME
is /home/alice, so change accordingly to your own $HOME
.
Copy the default config file if not already done¶
Create a directory ~/.cozy
and copy the default configuration file into it. Be careful, the file name and location matter, as explained in the config documentation.
cp cozy-stack/cozy.example.yaml ~/.cozy/cozy.yaml`
Edit the config file¶
Edit the file ~/.cozy/cozy.yaml
and change the line after the konnectors:
entry to have this:
cmd: /home/alice/.cozy/scripts/konnector-node-run.sh
[Optional] Then, after the entry fs:
url: file:///home/alice/.cozy/storage
Create the script to execute the service¶
Copy the file cozy-stack/scripts/konnector-node-run.sh
to ~/.cozy/konnector-node-run.sh
:
Then you need to chmod +x ~/.cozy/scripts/konnector-node-run.sh
Be sure to have node
in your /usr/bin
or /usr/local/bin
folder. If not, you can add a symlink to node
in one of those folder, for example by typing ln -s $(which node) /usr/local/bin/node
Get your service logs in a isolated file¶
Edit your ~/.cozy/konnector-node-run.sh
by adding a tee output.
set -o pipefail node "${arg}" 2>&1 | tee -a ~/.cozy/services.log
Now you can tail -f ~/.cozy/services.log
to watch logs in real time.
Install your app¶
To install the app containing the service on your local stack, you must give the path of your build:
cozy-stack apps install <app_name> file://<build_path> # Example: # cozy-stack apps install banks file:///home/alice/cozy-banks/build
Each time you make modifications to your service, you must update the app on the stack to propagate the changes:
cozy-stack apps update <app_name>
Env variables¶
When executing a service, cozy-stack injects some environment variables, listed here, so you can use them in your service, typically through process.env.<env_var_name>
.
Execution¶
The service will be run each time the trigger condition is met, e.g. a bank operation.
However, you can force its execution thanks to the cozy-konnector-dev
CLI, which can be useful for developement. Be aware, that in that case, you can’t rely on any of the stack provided variables
To install locally:
yarn add --dev cozy-jobs-cli
To run:
yarn run cozy-konnector-dev -m <app_manifest> <mybuiltservice.js>
Be carefull the mybuiltservice.js
must be the built file of your service, not the source.
If your mybuiltservice.js
is not executable and not recognize by node, you may need this script in your app folder to fix that. Just change the target
path.
#!/bin/bash target="build/services/sync-index-displayName/contacts.js" firstChar=$(head -c 1 $target) chmod +x $target if [[ $firstChar != \#* ]]; then sed -i '' '1i\ #!/usr/bin/env node ' $target fi cozy-konnector-dev -m manifest.webapp $target