Skip to content

Commit 5120f48

Browse files
committed
Merge branch 'martindekov/add_on_time_blog'
Closes: #181 Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2 parents fbd7cb7 + 24db0c2 commit 5120f48

2 files changed

Lines changed: 264 additions & 0 deletions

File tree

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
---
2+
title: Keep your functions running to schedule with the cron-connector.
3+
description: "In this post Martin will show you how to schedule your functions with the cron-connector, for regular tasks and scheduled jobs"
4+
date: 2020-05-14
5+
image: /images/2020-05-14-schedule-your-functions/accuracy-alarm-clock-analogue-business.jpg
6+
categories:
7+
- cron
8+
- kubernetes
9+
- serverless
10+
- linux
11+
- tutorial
12+
- example
13+
author_staff_member: martin
14+
dark_background: true
15+
16+
---
17+
18+
In this post Martin will show you how schedule your functions with the cron-connector, for regular tasks and scheduled jobs.
19+
20+
One of the things we need very often is our functions to be executed on a schedule. This is where the cron-connector shines. For our example we will create `Lockbot` which will lock conversation on outdated issues. With the `cron-connector` your functions will run on time.
21+
22+
## Motivation
23+
24+
OpenFaaS provides a very convenient and flexible way to quickly write and expose your code to be used by external systems. Often times those systems don't have a hook to which you can schedule function execution. Also very often we need to run those functions without external systems, we just want our code to be ran on an interval.
25+
26+
For those purposes [connector-sdk](https://github.com/openfaas-incubator/connector-sdk) was created. It provides the means to quickly adapt different systems to invoke functions. Some of them are [Kafka](https://github.com/openfaas-incubator/kafka-connector), [NATS](https://github.com/openfaas-incubator/nats-connector), [MQTT](https://github.com/openfaas-incubator/mqtt-connector) and [many more](https://docs.openfaas.com/reference/triggers/).
27+
28+
Now we need our functions to to be invoked on an interval. [Cron](https://en.wikipedia.org/wiki/Cron) is often used on GNU/Linux systems to execute tasks to a pre-defined schedule. In Kubernetes, this was abstracted into the `CronJob` object. For any OpenFaaS cluster, the [cron-connector](https://github.com/openfaas-incubator/cron-connector) uses the `connector-sdk` to provide the same functionality, running our functions on a predefined schedule.
29+
30+
Now lets roll up our sleeves and see how we can execute our OpenFaaS functions on time.
31+
32+
## Prerequisites
33+
34+
Before we start we need a couple of tools to help us quickly set up our environment:
35+
36+
* [docker](https://docs.docker.com/get-docker/) - the container runtime used in this post
37+
* [kubernetes](https://kind.sigs.k8s.io/docs/user/quick-start/) - cluster which will manage our containers
38+
* [arkade](https://github.com/alexellis/arkade) - one line installation of applications with which we will install OpenFaaS
39+
* [faas-cli](https://docs.openfaas.com/cli/install/) - the CLI which communicates with the OpenFaaS gateway
40+
* [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) - the CLI which communicates with your Kubernetes cluster
41+
42+
## Prepare environment
43+
44+
Before showing you how to run our functions on a schedule, first we need to set up the environment with the tools mentioned above.
45+
46+
### Create cluster
47+
48+
First thing we need is running Kubernetes cluster:
49+
50+
```bash
51+
kind create cluster
52+
```
53+
54+
Wait for the installation to finish and verify the pods in the `kube-system` namespace are `1/1`:
55+
56+
```bash
57+
kubectl get pods -n kube-system
58+
```
59+
60+
### Install OpenFaaS
61+
62+
With `arkade` the installation of OpenFaaS boils down to single line command:
63+
64+
```bash
65+
arkade install openfaas
66+
```
67+
68+
Wait for the OpenFaaS gateway to be ready:
69+
70+
```bash
71+
kubectl rollout status -n openfaas deploy/gateway
72+
```
73+
74+
Follow the instructions provided by `arkade` after the installation to set up the `faas-cli`. Also we will use Dockerhub to store the images so before we continue set `OPENFAAS_PREFIX`:
75+
76+
```bash
77+
export OPENFAAS_PREFIX="<dockerhub_username>"
78+
```
79+
80+
## Schedule the functions
81+
82+
After we have the environment up and running, now we can install the cron-connector and schedule our functions to run at specific intervals.
83+
84+
### Deploy the cron-connector
85+
86+
In order to install our `cron-connector` and schedule a function run the following command:
87+
88+
```bash
89+
arkade install cron-connector
90+
```
91+
92+
Wait for the `cron-connector` to be deployed:
93+
94+
```bash
95+
kubectl rollout status -n openfaas deploy/cron-connector
96+
```
97+
98+
The cron connector has a [helm chart](https://github.com/openfaas/faas-netes/tree/master/chart/cron-connector) which you can explore.
99+
100+
## How to schedule
101+
102+
The schedule of the function is configured through the `schedule` annotation following the normal cron syntax `* * * * *`. See [this](https://www.cyberciti.biz/faq/how-do-i-add-jobs-to-cron-under-linux-or-unix-oses/) blog post for some examples of the cron format.
103+
104+
Couple of quick cron schedule examples are:
105+
106+
* `*/5 * * * *` - will run once every five minutes
107+
* `0 0 */1 * *` - will run once every day of the month at 00:00
108+
* `0 0 * * */7` - will run once a week on the seventh day at 00:00
109+
110+
The cron-connector recognizes which functions should be ran on a schedule by annotation `topic` with value `cron-function`, we can add this annotation to the function's configurtion or during deployment
111+
112+
Now lets go head and create a function which will run on a schedule.
113+
114+
## Meet Lockbot
115+
116+
The `Lockbot` will run once per day at `00:00` and will check for old GitHub issues. The issue will be locked in case it is older than the days we will chose. For our example we can go with 3 months, which is roughly 90 days.
117+
118+
### Get the function template from store
119+
120+
The OpenFaaS framework has rich variety of language templates which you can use to write your own functions. In our example we will use Python 3 with the Debian based template `python3-flask-debian`:
121+
122+
```bash
123+
faas-cli template store pull python3-flask-debian
124+
```
125+
126+
### Generate the function
127+
128+
In order to generate the function's backbone we will run the following command:
129+
130+
```bash
131+
faas-cli new lockbot --lang python3-flask-debian
132+
```
133+
134+
### Generate access token
135+
136+
Go to the [personal access tokens](https://github.com/settings/tokens) page in GitHub and press the `Generate new token` button. The bot will use this to authenticate to the repository you chose.
137+
138+
Now copy the generated token and create `auth-token` secret using the `faas-cli` where you need to replace the `<token>` with the actual copied access token:
139+
140+
```bash
141+
faas-cli secret create auth-token --from-literal='<token>'
142+
```
143+
144+
### Configure the function
145+
146+
Open the function's configuration file called `stack.yml`. Append the following lines to the file:
147+
148+
```yml
149+
environment:
150+
github_repository: <repository>
151+
inactive_days: 90
152+
exec_timeout: 30s
153+
read_timeout: 30s
154+
write_timeout: 30s
155+
secrets:
156+
- auth-token
157+
annotations:
158+
topic: cron-function
159+
schedule: "0 0 */1 * *"
160+
```
161+
162+
> The schedule used `0 0 */1 * *` means once every day of the month at 00:00
163+
164+
We have increased the default timeout of the function to `30s`. Replace `<repository>` with one of your own repositories. The whole `stack.yml` file should look something like this:
165+
166+
```yml
167+
version: 1.0
168+
provider:
169+
name: openfaas
170+
gateway: http://127.0.0.1:31112
171+
functions:
172+
lockbot:
173+
lang: python3-flask-debian
174+
handler: ./lockbot
175+
image: martindekov/lockbot:latest
176+
environment:
177+
github_repository: push2
178+
inactive_days: 90
179+
exec_timeout: 30s
180+
read_timeout: 30s
181+
write_timeout: 30s
182+
secrets:
183+
- auth-token
184+
annotations:
185+
topic: cron-function
186+
schedule: "0 0 */1 * *"
187+
```
188+
189+
> The `image` and `repository` should be different
190+
191+
### Augment the code
192+
193+
Inside the `lockbot` folder you can see the `handler.py` file which contains the `handle` method which is the entry point to your function. Replace what's inside with the lockbot's code:
194+
195+
```python
196+
import os
197+
from datetime import datetime
198+
from github import Github
199+
200+
201+
def get_issues():
202+
desired_repo = os.getenv("github_repository")
203+
desired_days = int(os.getenv("inactive_days"))
204+
auth = None
205+
with open("/var/openfaas/secrets/auth-token") as file:
206+
auth = Github(file.read().strip())
207+
208+
issues_for_lock = []
209+
for repo in auth.get_user().get_repos():
210+
if repo.name == desired_repo:
211+
for issue in repo.get_issues():
212+
if not issue.pull_request and not issue.locked:
213+
last_comment = issue.get_comments()[
214+
issue.comments-1].updated_at
215+
difference = datetime.now() - datetime(last_comment.year,
216+
last_comment.month,
217+
last_comment.day)
218+
if difference.days > desired_days:
219+
issues_for_lock.append(issue)
220+
221+
return issues_for_lock
222+
223+
224+
def lock(issues):
225+
response = "no unlocked inactive issues"
226+
if len(issues) > 0:
227+
response = "issues locked:"
228+
for issue in issues:
229+
issue.lock("off-topic")
230+
response = response + f"\n{issue.title}"
231+
return response
232+
233+
234+
def handle(req):
235+
issues = get_issues()
236+
response = lock(issues)
237+
return response
238+
```
239+
240+
Finally add the Github SDK to the `requirements.txt` which is in the same folder as `handler.py`:
241+
242+
```text
243+
PyGithub
244+
```
245+
246+
The function will fetch the issues from the repository you chose in the configuration section then it will filter them and calculate, using the date when they were opened, whether they are older than the 90 days we chose. If this is the case the lockbot will authenticate itself against the GitHub API with the access token we generated and will lock the issue from further conversation, marking it as `off-topic`. The lockbot will respond with the locked issues or the lack of such.
247+
248+
### Deploy the function
249+
250+
Deploy lockbot so that it can start locking inactive issues on your GitHub repositories:
251+
252+
```bash
253+
faas up -f lockbot.yml
254+
```
255+
256+
A full working example of the function can be see in the [lockbot](https://github.com/martindekov/lockbot) repository.
257+
258+
>Note: To see the function in action you can directly invoke it using the UI or the CLI.
259+
260+
## Wrapping up
261+
262+
In this post we have shown how you can run minimal OpenFaaS environment with simple function and how with the help of the cron-connector you can execute the function on a desired schedule.
263+
264+
Learn how to create your own functions with the [OpenFaaS workshop](https://github.com/openfaas/workshop) and all the ways you can [trigger them](https://docs.openfaas.com/reference/triggers/). We used one of the templates from the store in our example, but you'll find many others, just run `faas-cli template store list` or view the [Template Documentation](https://docs.openfaas.com/cli/templates/) and make sure your functions always run on time!
220 KB
Loading

0 commit comments

Comments
 (0)