Skip to content

Commit

Permalink
Add Cloud Scheduler sample [(#1968)](#1968)
Browse files Browse the repository at this point in the history
* scheduler sample

* scheduler tutorial draft

* create and delete requests completed

* updated region tag

* update error

* fix linting

* Update styling

* Update license

* Update license

* Update license

* Update license
  • Loading branch information
averikitsch authored and dandhlee committed Apr 22, 2023
1 parent 8bfa093 commit 05c1241
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 0 deletions.
Empty file added scheduler/snippets/README.md
Empty file.
18 changes: 18 additions & 0 deletions scheduler/snippets/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/snippets/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/snippets/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/snippets/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/snippets/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/snippets/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

0 comments on commit 05c1241

Please sign in to comment.