Create a Custom Actor¶
This guide will demonstrate how to create a custom actor from scratch. It is assumed you are already familiar with how to Work with Actors. In this example, we will build a simple word count actor that counts and prints the number of words in a provided message.
Components of an Actor¶
Make a new directory and add the following files:
$ mkdir word-count-actor/ && cd word-count-actor/
$ touch Dockerfile word_count.py environment.json
$ tree ../word-count-actor/
word-count-actor/
├── Dockerfile
├── environment.json
└── word_count.py
0 directories, 3 files
Write the Actor Function¶
The word_count.py
python script is where the code for your main function can
be found. An example of a functional actor that performs a word count is:
#!/usr/bin/env python
from agavepy.actors import get_context
def main():
context = get_context()
message = context['raw_message']
try:
word_count = len(message.split(' '))
print('The number of words is: ' + str(word_count))
except Exception as e:
print('An unexpected error has occurred: ' + e)
if __name__ == '__main__':
main()
This code makes use of the agavepy python library which we will install in
the Docker container. The library includes an “actors” object which is useful to
grab the message and other context from the environment. And, it can be used to
interact with other parts of the Tapis platform. Add the above code to your
word_count.py
file.
Define Environment Variables¶
The environment.json
file may contain useful environment variables or
configurations to pass to the actor at creation time. These variables will be
part of the “context” taken from the environment, as in the example python
script above. For the purposes of this example, add the following definition to
environment.json
:
{
"foo": "bar"
}
Create a Dockerfile¶
The only requirements are python and the agavepy python library, which is
available through
PyPi.
A bare-bones Dockerfile needs to satisfy those dependencies, add the actor
python script, and set a default command to run the actor python script. Add
the following lines to your Dockerfile
:
FROM python:3.7-slim
RUN pip install --no-cache-dir agavepy==0.9.3
ADD word_count.py /word_count.py
RUN chmod +x /word_count.py
CMD ["python3", "/word_count.py"]
Tip
Creating small Docker images is important for maintaining actor speed and efficiency
Build and Push the Dockerfile¶
The Docker image must be pushed to a public repository in order for the actor to use it. Use the following Docker commands in your local actor folder to build and push to a repository that you have access to:
# Build and tag the image
$ docker build -t taccuser/word-count:1.0 .
Sending build context to Docker daemon 4.096kB
Step 1/5 : FROM python:3.7-slim
...
Successfully built b0a76425e8b3
Successfully tagged taccuser/word-count:1.0
# Push the tagged image to Docker Hub
$ docker push taccuser/word-count:1.0
The push refers to repository [docker.io/taccuser/word-count]
...
1.0: digest: sha256:67cc6f6f00589d9ae83b99d779e4893a25e103d07e4f660c14d9a0ee06a9ddaf size: 1995
Create the Actor¶
Next, create an actor referring to the Docker repository above. Also, pass the JSON file containing environment variables:
$ tapis actors create --repo taccuser/word-count:1.0 \
-n word-count \
-d "Count the number of words in the message" \
-E environment.json
+----------------+----------------------------+
| Field | Value |
+----------------+----------------------------+
| id | KKP0jKRGJ5l5K |
| name | word-count |
| owner | taccuser |
| image | taccuser/word-count:1.0 |
| lastUpdateTime | 2020-05-15 18:00:33.685417 |
| status | SUBMITTED |
+----------------+----------------------------+
After a few seconds, the actor should be in state “READY”, meaning it is ready
to accept and process messages. Verbosely show the actor metadata to see that
it’s status is “READY”, it is pointing to the correct docker image, and that it
received the environment variables from environment.json
:
$ tapis actors show -v KKP0jKRGJ5l5K
{
"id": "KKP0jKRGJ5l5K",
"name": "word-count",
"description": "Count the number of words in the message",
"owner": "taccuser",
"image": "taccuser/word-count:1.0",
"createTime": "2020-05-15 18:00:33.685417",
"lastUpdateTime": "2020-05-15 18:00:33.685417",
"defaultEnvironment": {
"foo": "bar"
},
"gid": 851953,
"hints": [],
"link": "",
"mounts": [],
"privileged": false,
"queue": "default",
"stateless": true,
"status": "READY",
"statusMessage": " ",
"token": true,
"uid": 851953,
"useContainerUid": false,
"webhook": "",
"_links": {
"executions": "https://api.tacc.utexas.edu/actors/v2/KKP0jKRGJ5l5K/executions",
"owner": "https://api.tacc.utexas.edu/profiles/v2/taccuser",
"self": "https://api.tacc.utexas.edu/actors/v2/KKP0jKRGJ5l5K"
}
}
Run a Test Execution¶
Finally, pass a message to the actor to run a test execution. The number of words in the message should be returned in the actor execution logs:
# Send a message to the word-count actor
$ tapis actors submit -m "This is a test message with 8 words" KKP0jKRGJ5l5K
+-------------+-------------------------------------+
| Field | Value |
+-------------+-------------------------------------+
| executionId | K1p3AZZpXjwZr |
| msg | This is a test message with 8 words |
+-------------+-------------------------------------+
# List executions of the word-count actor
$ tapis actors execs list KKP0jKRGJ5l5K
+---------------+----------+
| executionId | status |
+---------------+----------+
| K1p3AZZpXjwZr | COMPLETE |
+---------------+----------+
# Get the logs from the completed actor execution
$ tapis actors execs logs KKP0jKRGJ5l5K K1p3AZZpXjwZr
Logs for execution K1p3AZZpXjwZr
The number of words is: 8
The actor can also be run synchronously using tapis actors run
:
$ tapis actors run -m "This is an example of running the actor synchronously" KKP0jKRGJ5l5K
The number of words is: 9
Next Steps¶
Remember to put your actor under version control. Use a .gitignore
file to
avoid accidentally committing anything that contains API keys or passwords.
Please refer to the Abaco Documentation for more information on creating and working with actors.