Skip to content

Commit 2265fc6

Browse files
authored
AWS Batch - Submit Job (#6)
* Update role to allow lambda function to submit AWS Batch jobs * Add support to submit aws batch jobs * Update diagrams for batch * Update README for supporting AWS Batch * Update json schema for AWS Batch
1 parent 8a34ffe commit 2265fc6

File tree

8 files changed

+120
-3
lines changed

8 files changed

+120
-3
lines changed

README.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Tasks are scheduled using the same syntax for expressions as linux
1313

1414
* **Queue task**: send message to AWS SQS queue.
1515
* **Lambda task**: invoke AWS lambda function.
16+
* **Batch task**: submit AWS Batch job.
1617
* **HTTP task**: send HTTP requests (GET & POST).
1718

1819
Tasks are defined in YAML files and are stored in a S3 bucket.
@@ -283,7 +284,7 @@ All parameters of the function will be supported soon.
283284
### Lambda task
284285
285286
It invokes an AWS lambda functions.
286-
The task definition must contains following keys
287+
The task definition must contains following keys:
287288
288289
* **type**: *lambda*
289290
* **FunctionName**: Name of the lambda function to invoke (string)
@@ -302,6 +303,29 @@ task:
302303
303304
Function is invoked using [boto3 Lambda.Client.invoke_async](http://boto3.readthedocs.io/en/latest/reference/services/lambda.html#Lambda.Client.invoke_async)
304305
306+
### Batch task
307+
308+
It submits AWS Batch Jobs.
309+
The task definition must contains following keys:
310+
311+
* **type**: *batch*
312+
* **jobName**: name to assign to the job (string)
313+
* **jobQueue**: name of the queue in AWS Batch (string)
314+
* **jobDefinition**: name of the job definition in AWS Batch (string)
315+
316+
``` yaml
317+
name: 'Enrich new stats every hour'
318+
expression: '0 * * * *'
319+
task:
320+
type: 'bath'
321+
jobName: 'enrich-stats'
322+
jobDefinition: 'enrich-stats-definition:1'
323+
jobQueue: 'jobs_high_priority'
324+
```
325+
326+
It is a wrapper for [boto3 Batch.Client.submit_job](http://boto3.readthedocs.io/en/latest/reference/services/batch.html#Batch.Client.submit_job).
327+
It means all parameters for the method can be set in the task definition.
328+
305329
### HTTP task
306330
307331
It send and HTTP request (GET or POST).

lambda-cron-diagram.png

7.21 KB
Loading

lambda-cron-diagram.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<mxfile userAgent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" version="6.1.0.2" editor="www.draw.io" type="device"><diagram name="Page-1">7VpLk9o4EP41HHH5gW04DpNk97Cpmqockj1Rwha2amTLkeUB8utXsi1AfoAINqS2gANW69nf12qp20yc12T3FwVZ/JWEEE9sM9xNnE8T27Yc1+M/QrKvJP5sUQkiisK60VHwDf2CtdCspQUKYa40ZIRghjJVGJA0hQFTZIBSslWbbQhWZ81ABFuCbwHAbel3FLK4ks5d8yj/G6IoljNbZl2zBsF7REmR1vNNbGdTfqrqBMix6vZ5DEKyPRE5nyfOKyWEVU/J7hViga2Erer3paf2sG4KU6bTwa46fABcQLnicl1sL7EIQR5D0dycOMuYJZg/WvyRLz0TTZJdJIzAANvcNnJGKAdnBdJwxclhfBkrbhzoA9K9kTurdRG8QyZ6M0re4SvBhPIxUpLyoZb1YiBlcNerkHWAiZsfJAlkdM+byA5zv+pSW54jOdseeXRnlSg+oVBaLKgtJzqMfESPP9QAdoPpDAxmQJKsYBWYKWRbQt9RGhkYJOsQjIrhXMHQNjswXLQx9O3bMZz9TzCcScwegKE3MIYgy1Y5pB8ogLmR/8xXPwsoRr4beJbjtcDz3DZ4swHA8wcGD3EnSLnlrchmxWJue7kRM5atMkoYCQi+pw0u3BaMvtnhCxe3wzi/DCNMwxdxVvNSgEGeo0CFs+oAw9ZRfVH/0z3WpV8toxADxo8m9frQoXQ9wxvhZB7htc2FetTMTHWInBQ0gHWv00P4wkD2vDEQAzSCrDVQycFBbS1aFo+kRapr9airSdsVDFlDMdS35OEZklfgx1Jk340ieyiK+pY8AkUat+ZLFHEi6P5HfYaUhX9FwXBl8Q1SxNcEqWyzQ+yH7MyfT5rzUrO1rgXwNZf4KhfYCqmT+9ijPKy1UA+wWZNTbeOYNQZyxjMOjSjgTsZhW2Nbh3fei3gq6o49mhdxGzedJr/ahtK35BEMRSPUuZOh+IuxDcU/byh+A3VnNENpzrT4XUPpW/LwhuJqGIqIE1AA8D9gDfEbyRFDJOVVa8IYSVSjkW1fMIpEG0ayVhAysR2v/PCaDcL4RL4sv13hzq+CQiMPeGxUYGFCg+QiXPVYt3yrZRoyOhw8FNS4iolkX9arZ52fBGvZ3Lxaf6mc9GzevKW/17E15s7t+nt30d83zwIwbYf+TpcrGEBfVyNo7dhHvXsOi4rlISN8sofqnPD5vSgzz/Y1u3Pjim+1O6vMsvDjSsaiuW8RyX0DcapyIyRBkZTM6O1d7zx37XSDHOSUuqbn/C3qNAJbqTdKyuz/ZZc4BMHlZC95Vr2lEPADWdigneBkWa/nk0gLcQhehNL2lyBMrZKVDUpDSEUik0tDwAD/KdnivzHY1k+OwMo3TdO3p6J26syn3DTgdJ/gqWXPjSyNbqL0cLPS2o5DcOpZf4D7mamnT/teMpYz8jSCzKczUiz3/El6P2fkaYSAT2d0C6UPcEYal/DRnZGleqOOcHo0b+Q+vdGV3qgnc3Z/b6TxOvDpjW6h9AHeSOMt5ejeSCqyV4v38EbPQO1ab3Q+ATdtJ1VGc0fPSG0od9TD6f3dka8RqY3/zrL5b4fx3lk2ZrrhxX/Pkm9OIvPi8U+EVfPjPzWdz/8B</diagram></mxfile>
2+
<mxfile userAgent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" version="6.2.4" editor="www.draw.io" type="device"><diagram name="Page-1">7VrLcqM6EP0aL02BeHqZOJOZxdxbqcpi5q4oGWRbFUCMkGM7X38lQLZlwJZjcKZmkiwMjV59TqulbmlkT9PNVwrz5T8kRskImPFmZD+MALCsicl/hGRbSTynFiwojutCe8EzfkO1UBZb4RgVSkFGSMJwrgojkmUoYooMUkrWarE5SdRec7hADcFzBJOm9AeO2bKSBq65l39DeLGUPVtm/WUGo5cFJaus7m8E7Hn5V31OoWyrLl8sYUzWByL7y8ieUkJY9ZRupigR2ErYqnqPHV9346YoYzoVQFXhFSYrJEdcjottJRYxLJZIFDdH9v2SpQl/tPgjH3ouiqSbhTACA64LYBSMUA5OCLM45OQwPoyQGwd+RXRrFHY4W0UviInajJIXNCUJobyNjGS8qfvm6GuFeHWGNgeiWpuviKSI0S0vIr8GflWltjxbcrbe8+g6lWh5QKHr1dZTW85i1/IePf5QA9gOpt0zmBFJ8xWrwMwQWxP6grOFkcB0FsNBMQwUDIHZguGkiaEPrsfQ+UMwdExbwdCSBnaIod/E0HOux9DrGUOY52GB6CuOUGEUv4rw1wqJlm8G3sTRws7uYQ77PWOHuQ+k3PBCMg/ZkpteYSwZy8OcEkYiktwQRVs2cQgjaIFxcj2MwXkYURbfiaWav0UJLAocqXB2IoBiZfFu6n+on9ni6msZRQlkfGVSdw8tStc9PBFO5h5eYE5UeOUeRzZRkBWNUF3rcA0+0xAIjhpikC4QazRUcrBTW4uWyUfSItW1OtTVpO0Chqy+GOoacv8MyR3wx1IEbkYR6IuiriEPQJHGpvkcRZwZuv1ZryHly3/ixXDl6xOimI8JUVlmg9lPWZk/HxTnb8elOy2gglPZrlbAKLuv38TD7sLImlPnmFNt43COGrKHMw6NIOBGxgGsnq3Du9CLeCrqNhjMi7hqT+CYX21D6RryAIaiEencyFD8Sc+G4l9oKP4R6vZghnLc0+S9htI15P4NxdUwFBEU4Agm3+EMJU+kwAyTjH+aEcZIqhqNLHuX4IUow0jeCEJGPJYq//iXOU6SA/l9+d8W7rytKDKKiMdGq0SYUC+pCFdd1i2/GcPIsO/QNBzQbRraoaDGVkzk+nJ9PXcZSziTLZin9ZfKSc/mBQ39vZapEdjX6++9X/8ddFcDMG6mTew2V9CDvq5G0NoyjzrnXCI+3O8SwgdzqE4Jn56LMvEMLpmdc1f8V7OzSiwLP65kLI7nLSaFb2BOS2HEJFqlJYktc9fr4rSTO7dBnTQCJd1wwotrU6cR2Eq9cVom/8+7xD4ILju7K/LqkELAD+XLHG8EJ/f1eB5EWohDcCeUBo9RnFklK3OcxYiKPCaXxpBB/lOyxX+XcF0/2QIr3zRNH4zF17EdjLlpoPE2TcYWCIw8W1xF6W5npTUd++DUs85zOrj7cdTVp7kvGcoZeRpB5t/sjC7eSdzOGXkaIeCnM7qG0g9wRhqb8MGdkaV6o5ZwejBv5H56o1PeyOmg+HfwRhqngZ/e6BpKP8AbaZxSDu6NpCJb9fUW3ugzUDvpjfwOiruD7GZSZTB39Bmpvcsd6XN6e3fka0Rqw59Zmqo/GvDM8qinKw7+O4bcfxJZXs36o6YdODvtYArf+BSD62JcMJRFOBHS8rbm47S+GRb+u7sWFkYk34Z3P57DB0z5IMJptSTu5mV3NrxzVW2YdPeCGhzlekEz9xm0XLuTsqumcB/HlhcdUe/PrgwrAJrnV60u4V0nVOC0M3HVW6TWpJl27+voUu0JOEeX2HSdiWPZ7UO+2pnw1/2F5Kr4/ta3/eV/</diagram></mxfile>

lambda_cron/aws/lib/task_runner.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ def get_lambda_task_runner(self, task):
4242
def get_http_task_runner(self, task):
4343
return HttpTask(task)
4444

45+
def get_batch_task_runner(self, task):
46+
return BatchJobTask(task)
47+
4548

4649
class Task:
4750

@@ -84,3 +87,13 @@ def run(self):
8487
FunctionName=self.task['FunctionName'],
8588
InvokeArgs=json.dumps(self.task['InvokeArgs'])
8689
)
90+
91+
92+
class BatchJobTask(Task):
93+
94+
def get_batch_client(self):
95+
return boto3.client('batch')
96+
97+
def run(self):
98+
self.task.pop('type')
99+
self.get_batch_client().submit_job(**self.task)

lambda_cron/schema.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@
2828
},
2929
"required": ["type", "FunctionName", "InvokeArgs"]
3030
},
31+
{
32+
"properties": {
33+
"type": { "type": "string", "enum": ["batch"] },
34+
"jobName": { "type": "string" },
35+
"jobQueue": { "type": "string" },
36+
"jobDefinition": { "type": "string" },
37+
"dependsOn": { "type": "array" },
38+
"parameters": { "type": "object" },
39+
"containerOverrides": { "type": "object" }
40+
},
41+
"required": ["type", "jobName", "jobQueue", "jobDefinition"]
42+
},
3143
{
3244
"properties": {
3345
"type": { "type": "string", "enum": ["http"] },

lambda_cron/template.cfn.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ Resources:
8787
Action:
8888
- lambda:InvokeFunction
8989
Resource: ['*']
90+
- Effect: Allow
91+
Action:
92+
- batch:SubmitJob
93+
Resource: ['*']
9094

9195
LambdaCronHourlyEvent:
9296
Type: AWS::Events::Rule
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name: 'test batch task'
2+
expression: '0 11 * * *'
3+
task:
4+
type: 'batch'
5+
jobName: 'my-batch-job'
6+
jobQueue: 'job-queue-hihg-priority'
7+
jobDefinition: 'my-batch-job-definition'
8+
parameters:
9+
argument_1: 'value_argument_1'
10+
argument_2: 2

tests/test_task_runner.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import pytest
1616
import json
1717
from mock import patch
18-
from lambda_cron.aws.lib.task_runner import TaskRunner, QueueTask, InvokeLambdaTask, HttpTask
18+
from lambda_cron.aws.lib.task_runner import TaskRunner, QueueTask, InvokeLambdaTask, HttpTask, BatchJobTask
1919
from lambda_cron.aws.lib.cron_checker import CronChecker
2020

2121

@@ -323,3 +323,57 @@ def test_http_not_supported_method(get_requests_client_mock, http_client_spy, cr
323323
with pytest.raises(Exception) as exception_info:
324324
task_runner.run(http_get_task_definition)
325325
assert "Http method not supported: put" in str(exception_info.value)
326+
327+
328+
class BatchClientSpy:
329+
def __init__(self):
330+
self.parameters = None
331+
self.calls = 0
332+
333+
def submit_job(self, **kwargs):
334+
self.parameters = kwargs
335+
self.calls += 1
336+
337+
338+
@pytest.fixture(scope="function")
339+
def batch_client_spy():
340+
return BatchClientSpy()
341+
342+
343+
BATCH_TASK_BODY =\
344+
{
345+
'type': 'batch',
346+
'jobName': 'testing-batch-job',
347+
'jobQueue': 'testing-batch-job-queue',
348+
'jobDefinition': 'testing-batch-job-definition',
349+
'parameters':
350+
{
351+
'param_1': 'value_1',
352+
'param_2': 'value_2'
353+
}
354+
}
355+
356+
357+
@pytest.fixture(scope="function")
358+
def batch_task_definition():
359+
return {
360+
'name': 'Test task',
361+
'expression': '0 11 * * *',
362+
'task': dict(BATCH_TASK_BODY)
363+
}
364+
365+
366+
@patch.object(BatchJobTask, 'get_batch_client')
367+
def test_batch_should_run_basic(get_batch_client_mock, batch_client_spy, cron_checker, batch_task_definition):
368+
get_batch_client_mock.return_value = batch_client_spy
369+
370+
task_runner = TaskRunner(cron_checker)
371+
task_runner.run(batch_task_definition)
372+
373+
assert batch_client_spy.calls == 1
374+
assert 'jobName' in batch_client_spy.parameters
375+
assert batch_client_spy.parameters['jobName'] == 'testing-batch-job'
376+
assert 'jobQueue' in batch_client_spy.parameters
377+
assert batch_client_spy.parameters['jobQueue'] == 'testing-batch-job-queue'
378+
assert 'parameters' in batch_client_spy.parameters
379+
assert batch_client_spy.parameters['parameters'] == BATCH_TASK_BODY['parameters']

0 commit comments

Comments
 (0)