Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Cloud Scheduler sample #1968

Merged
merged 14 commits into from
Jul 24, 2019
Empty file added scheduler/README.md
Empty file.
18 changes: 18 additions & 0 deletions scheduler/app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START cloud_scheduler_python_yaml]
runtime: python37
service: my-service
# [END cloud_scheduler_python_yaml]
77 changes: 77 additions & 0 deletions scheduler/create_job.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


def create_scheduler_job(project_id, location_id, service_id):
"""Create a job with an App Engine target via the Cloud Scheduler API"""
# [START cloud_scheduler_create_job]
from google.cloud import scheduler

# Create a client.
client = scheduler.CloudSchedulerClient()

# TODO(developer): Uncomment and set the following variables
# project_id = 'PROJECT_ID'
# location_id = 'LOCATION_ID'
# service_id = 'my-service'

# Construct the fully qualified location path.
parent = client.location_path(project_id, location_id)

# Construct the request body.
job = {
'app_engine_http_target': {
'app_engine_routing': {
'service': service_id
},
'relative_uri': '/log_payload',
'http_method': 'POST',
'body': 'Hello World'.encode()
},
'schedule': '* * * * *',
'time_zone': 'America/Los_Angeles'
}

# Use the client to send the job creation request.
response = client.create_job(parent, job)

print('Created job: {}'.format(response.name))
# [END cloud_scheduler_create_job]
return response


def delete_scheduler_job(project_id, location_id, job_id):
"""Delete a job via the Cloud Scheduler API"""
# [START cloud_scheduler_delete_job]
from google.cloud import scheduler
from google.api_core.exceptions import GoogleAPICallError

# Create a client.
client = scheduler.CloudSchedulerClient()

# TODO(developer): Uncomment and set the following variables
# project_id = 'PROJECT_ID'
# location_id = 'LOCATION_ID'
# job_id = 'JOB_ID'

# Construct the fully qualified job path.
job = client.job_path(project_id, location_id, job_id)

# Use the client to send the job deletion request.
try:
client.delete_job(job)
print("Job deleted.")
except GoogleAPICallError as e:
print("Error: %s" % e)
# [END cloud_scheduler_delete_job]
33 changes: 33 additions & 0 deletions scheduler/create_job_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright 2019 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os

import create_job

TEST_PROJECT_ID = os.getenv('GCLOUD_PROJECT')
TEST_LOCATION = os.getenv('LOCATION_ID', 'us-central1')


def test_create_job(capsys):
create_result = create_job.create_scheduler_job(
TEST_PROJECT_ID, TEST_LOCATION, 'my-service')
out, _ = capsys.readouterr()
assert 'Created job:' in out

job_name = create_result.name.split('/')[-1]
create_job.delete_scheduler_job(TEST_PROJECT_ID, TEST_LOCATION, job_name)

out, _ = capsys.readouterr()
assert 'Job deleted.' in out
42 changes: 42 additions & 0 deletions scheduler/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""App Engine app to serve as an endpoint for Cloud Scheduler samples."""

# [START cloud_scheduler_app]
from flask import Flask, request

app = Flask(__name__)


# Define relative URI for job endpoint
@app.route('/log_payload', methods=['POST'])
def example_task_handler():
"""Log the job payload."""
payload = request.get_data(as_text=True) or '(empty payload)'
print('Received job with payload: {}'.format(payload))
return 'Printed job payload: {}'.format(payload)
# [END cloud_scheduler_app]


@app.route('/')
def hello():
"""Basic index to verify app is serving."""
return 'Hello World!'


if __name__ == '__main__':
# This is used when running locally. Gunicorn is used to run the
# application on Google App Engine. See entrypoint in app.yaml.
app.run(host='127.0.0.1', port=8080, debug=True)
45 changes: 45 additions & 0 deletions scheduler/main_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Copyright 2019 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import pytest


@pytest.fixture
def app():
import main
main.app.testing = True
return main.app.test_client()


def test_index(app):
r = app.get('/')
assert r.status_code == 200


def test_log_payload(capsys, app):
payload = 'test_payload'

r = app.post('/log_payload', data=payload)
assert r.status_code == 200

out, _ = capsys.readouterr()
assert payload in out


def test_empty_payload(capsys, app):
r = app.post('/log_payload')
assert r.status_code == 200

out, _ = capsys.readouterr()
assert 'empty payload' in out
3 changes: 3 additions & 0 deletions scheduler/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Flask==1.0.2
gunicorn==19.9.0
google-cloud-scheduler==0.1.0