Before you begin to develop a custom application:
Make sure to have the Adobe I/O CLI installed locally.
To create a custom application, create an App Builder project. To do so, execute aio app init <app-name>
in your terminal.
If you have not logged in already, this command prompts a browser asking you to sign into the Adobe Developer Console with your Adobe ID. See here for more information on signing in from the cli.
Adobe recommends that you login. If you are having issues then follow the instructions to create an app without logging in.
After logging in, follow the prompts in the CLI and select the Organization
, Project
, and Workspace
to use for the application. Choose the project and workspace you created when you set up your environment. When prompted Which extension point(s) do you wish to implement ?
, make sure to select DX Asset Compute Worker
:
$ aio app init <app-name>
Retrieving information from Adobe I/O Console.
? Select Org My Adobe Org
? Select Project MyAdobe Developer App BuilderProject
? Which extension point(s) do you wish to implement ? (Press <space> to select, <a>
to toggle all, <i> to invert selection)
❯◯ DX Experience Cloud SPA
◯ DX Asset Compute Worker
When prompted with Which Adobe I/O App features do you want to enable for this project?
, select Actions
. Make sure to deselect Web Assets
option as web assets use different authentication and authorization checks.
? Which Adobe I/O App features do you want to enable for this project?
select components to include (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯◉ Actions: Deploy Runtime actions
◯ Events: Publish to Adobe I/O Events
◯ Web Assets: Deploy hosted static assets
◯ CI/CD: Include GitHub Actions based workflows for Build, Test and Deploy
When prompted Which type of sample actions do you want to create?
, make sure to select Adobe Asset Compute Worker
:
? Which type of sample actions do you want to create?
Select type of actions to generate
❯◉ Adobe Asset Compute Worker
◯ Generic
Follow the rest of the prompts and open the new application in Visual Studio Code (or your favorite code editor). It contains the scaffolding and sample code for a custom application.
Read here about the main components of an App Builder app.
The template application leverages our Asset Compute SDK for the uploading, downloading, and orchestration of application renditions so developers only need to implement the custom application logic. Inside the actions/<worker-name>
folder, the index.js
file is where to add the custom application code.
See example custom applications for examples and ideas for custom applications.
As you log in when creating the application, most of the App Builder credentials get collected in your ENV file. However, using the developer tool requires additional credentials.
The developer tool used to test custom applications with the actual Asset Compute service requires a cloud storage container for hosting test files and for receiving and displaying renditions generated by applications.
This is separate from the cloud storage of Adobe Experience Manager as a Cloud Service. It only applies for developing and testing with the Asset Compute developer tool.
Make sure to have access to a supported cloud storage container. This container can be shared by multiple developers across different projects as needed.
Add the following credentials for the developer tool to the ENV file in the root of your App Builder project:
Add the absolute path to the private key file created while adding services to your App Builder Project:
ASSET_COMPUTE_PRIVATE_KEY_FILE_PATH=
Download the file from the Adobe Developer Console. Go to the root of the project and click on “Download All” in the upper-right corner. The file is downloaded with <namespace>-<workspace>.json
as the filename. Do one of the following:
Rename the file as console.json
and move it in the root of your project.
Optionally, you can add the absolute path to the Adobe Developer Console integration JSON file. This is the same console.json
file that is downloaded in your project workspace.
ASSET_COMPUTE_INTEGRATION_FILE_PATH=
Add either S3 or Azure storage credentials. You only need access to one cloud storage solution.
# S3 credentials
S3_BUCKET=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=
# Azure Storage credentials
AZURE_STORAGE_ACCOUNT=
AZURE_STORAGE_KEY=
AZURE_STORAGE_CONTAINER_NAME=
The config.json
file contains credentials. From within your project, add the JSON file to your .gitignore
file to prevent its sharing. The same applies to the .env and .aio files.
Before executing the application with the Asset Compute Developer Tool, properly configure the credentials.
To run the application in the developer tool, use aio app run
command. It deploys the action to Adobe I/O Runtime and start the development tool on your local machine. This tool is used to test application requests during development. Here is an example rendition request:
"renditions": [
{
"worker": "https://1234_my_namespace.adobeioruntime.net/api/v1/web/example-custom-worker-master/worker",
"name": "image.jpg"
}
]
Do not use the --local
flag with the run
command. It does not work with Asset Compute custom applications and the Asset Compute Developer tool. Custom applications are called by the Asset Compute Service which cannot access actions running on developer’s local machines.
See here how to test and debug your application. When you are finished developing your custom application, deploy your custom application.
The following are example custom applications:
The worker-basic is a template application. It generates a rendition by simply copying the source file. The content of this application is the template received when choosing Adobe Asset Compute
in the creation of the aio app.
The application file, worker-basic.js
uses the asset-compute-sdk
to download the source file, orchestrate each rendition processing, and upload the resulting renditions back to cloud storage.
The renditionCallback
defined inside the application code, is where to perform all the application processing logic. The rendition callback in worker-basic
simply copies the source file contents to the rendition file.
const { worker } = require('@adobe/asset-compute-sdk');
const fs = require('fs').promises;
exports.main = worker(async (source, rendition) => {
// copy source to rendition to transfer 1:1
await fs.copyFile(source.path, rendition.path);
});
In the application code, you can make external API calls to help with application processing. An example application file invoking external API is below.
exports.main = worker(async function (source, rendition) {
const response = await fetch('https://adobe.com', {
method: 'GET',
Authorization: params.AUTH_KEY
})
});
For example, the worker-animal-pictures
makes a fetch request to a static URL from Wikimedia using the node-httptransfer
library.
You can pass custom defined parameters through the rendition objects. They can be referenced inside the application in rendition
instructions. An example of a rendition object is:
"renditions": [
{
"worker": "https://1234_my_namespace.adobeioruntime.net/api/v1/web/example-custom-worker-master/worker",
"name": "image.jpg",
"my-custom-parameter": "my-custom-parameter-value"
}
]
An example of a application file accessing custom parameter is:
exports.main = worker(async function (source, rendition) {
const customParam = rendition.instructions['my-custom-parameter'];
console.log('Custom paramter:', customParam);
// should print out `Custom parameter: "my-custom-parameter-value"`
});
The example-worker-animal-pictures
passes a custom parameter animal
to determine which file to fetch from Wikimedia.
By default, Asset Compute custom applications come with Authorization and Authentication checks for App Builder project. This is enabled by setting the require-adobe-auth
annotation to true
in the manifest.yml
.
Add the API services to the Asset Compute Console workspace created in setup. These services are part of the JWT access token generated by Asset Compute Service. The token and other credentials are accessible inside the application action params
object.
const accessToken = params.auth.accessToken; // JWT token for Technical Account with entitlements from the console workspace to the API service
const clientId = params.auth.clientId; // Technical Account client Id
const orgId = params.auth.orgId; // Experience Cloud Organization
To handle credentials for other external services, pass these as default parameters on the actions. These are automatically encrypted in transit. For more information, see creating actions in Runtime developer guide. Then set them using environment variables during deployment. These parameters can be accessed in the params
object inside the action.
Set the default parameters inside the inputs
in the manifest.yml
:
packages:
__APP_PACKAGE__:
actions:
worker:
function: 'index.js'
runtime: 'nodejs:10'
web: true
inputs:
secretKey: $SECRET_KEY
annotations:
require-adobe-auth: true
The $VAR
expression reads the value from an environment variable named VAR
.
During development, the value can be set in the local ENV file as aio
automatically reads environment variables from ENV files in addition to the variables set from the invoking shell. In this example, the ENV file looks like:
#...
SECRET_KEY=secret-value
For production deployment one might set the environment variables in the CI system, for example using secrets in GitHub Actions. Lastly, access the default parameters inside the application as such:
const key = params.secretKey;
An application executes in a container in Adobe I/O Runtime with limits that can be configured through the manifest.yml
:
actions:
myworker:
function: /actions/myworker/index.js
limits:
timeout: 300000
memorySize: 512
concurrency: 1
Due to the more extensive processing typically done by Asset Compute applications, it is more likely one has to adjust these limits for optimal performance (large enough to handle binary assets) and efficiency (not wasting resources due to unused container memory).
The default timeout for actions in Runtime is a minute but it can be increased by setting the timeout
limit (in milliseconds). If you expect to process larger files, increase this time. Consider the total time it takes to download the source, process the file and upload the rendition. If an action times out, i.e. does not return the activation before the specified timeout limit, Runtime discards the container and not reuse it.
Asset compute applications by nature tend to be network and disk Input or output bound. The source file has to be downloaded first, processing is often resource-intensive and then the resulting renditions are uploaded again.
The memory available to an action container is specified by memorySize
in MB. Currently this also defines how much CPU access the container gets, and most importantly it is a key element of the cost of using Runtime (larger containers cost more). Use a larger value here when your processing requires more memory or CPU but be careful to not waste resources as the larger the containers are, the lower the overall throughput is.
Furthermore, it is possible to control action concurrency within a container using the concurrency
setting. This is the number of concurrent activations a single container (of the same action) gets. In this model, the action container is like a Node.js server receiving multiple concurrent requests, up to that limit. If not set, the default in Runtime is 200, which is great for smaller App Builder actions, but usually too large for Asset Compute applications given their more intensive local processing and disk activity. Some applications, depending on their implementation, might also not work well with concurrent activity. The Asset Compute SDK ensures activations are separated by writing files to different unique folders.
Test applications to find the optimal numbers for concurrency
and memorySize
. Larger containers = higher memory limit could allow for more concurrency but could also be wasteful for lower traffic.