forked from confluentinc/demo-scene
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request confluentinc#245 from confluentinc/pytexas
Add Python Microservices project
- Loading branch information
Showing
24 changed files
with
897 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Random Pizza Generator | ||
an event-driven microservices demo with Python and Kafka | ||
|
||
## Description | ||
|
||
This demo consists of the following projects: | ||
|
||
- *pizza-service* a Flask app with Kafka support. | ||
- *sauce-service* a basic Python app with Kafka. | ||
- *cheese-service* a basic Python app with Kafka. | ||
- *meat-service* a basic Python app with Kafka. | ||
- *veggie-service* a basic Python app with Kafka. | ||
|
||
|
||
The demo was built using Confluent Cloud, the Cloud-native service for Apache Kafka. If you don't have an account on Confluent Cloud, you can set that up [here](https://www.confluent.io/confluent-cloud). | ||
|
||
## Running the demo | ||
|
||
Before running this demo, you will need to update the `config.properties` file in each project. Replace the fields marked with `< >` using values from your Confluent Cloud cluster. Also, you will need to create 5 topics in Confluent Cloud. They can each have 1 partion (or more if you so desire): `pizza`, `pizza-with-sauce`, `pizza-with-cheese`, `pizza-with-meat`, and `pizza-with-veggies`. | ||
|
||
Once all five services are up and running, you can issue the following `curl` command to send an order for 3 random pizzas. | ||
`curl -X POST -d http://localhost:5000/order/5` | ||
|
||
This will trigger a series of events which will result in a completed pizza order with the five pizzas, and it will return a UUID of that pizza order. Of course you can alter that last value in the URL to get a different number of pizzas. (I was a bit hungry when I wrote this.) | ||
|
||
To see your pizzas in all their hot, delicious glory, run the following `curl` command using the UUID returned from the first call. | ||
|
||
curl http://localhost:5000/order/{{pizza-order-UUID}} | jq | ||
|
||
Note: `jq` is optional, but very helpful. More info at https://stedolan.github.io/jq/ | ||
|
||
|
||
*When you are done working with this demo project, you can delete these topics to avoid additional charges.* | ||
|
||
|
||
## Related Documentation that might be helpful | ||
|
||
### Confluent Cloud | ||
|
||
[Quik-start Guide](https://docs.confluent.io/cloud/current/get-started/index.html) | ||
|
||
### Python and Kafka | ||
|
||
- [Quick-start Guide](https://developer.confluent.io/get-started/python) | ||
- [Python Kafka Client](https://docs.confluent.io/clients-confluent-kafka-python/current/overview.html) | ||
- [Python Kafka Articles](https://www.confluent.io/blog/tag/python/) | ||
|
||
--- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
[kafka_client] | ||
bootstrap.servers=<Kafka server or Confluent Cloud endpoint> | ||
security.protocol=SASL_SSL | ||
sasl.mechanisms=PLAIN | ||
sasl.username=<Confluent Cloud API Key> | ||
sasl.password=<Confluent Cloud API Secret> | ||
auto.offset.reset=earliest | ||
group.id=cheeses | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
from configparser import ConfigParser | ||
from confluent_kafka import Producer, Consumer | ||
import json | ||
import random | ||
|
||
config_parser = ConfigParser(interpolation=None) | ||
config_file = open('config.properties', 'r') | ||
config_parser.read_file(config_file) | ||
client_config = dict(config_parser['kafka_client']) | ||
|
||
cheese_producer = Producer(client_config) | ||
|
||
sauce_consumer = Consumer(client_config) | ||
sauce_consumer.subscribe(['pizza-with-sauce']) | ||
|
||
|
||
def start_service(): | ||
while True: | ||
msg = sauce_consumer.poll(0.1) | ||
if msg is None: | ||
pass | ||
elif msg.error(): | ||
pass | ||
else: | ||
pizza = json.loads(msg.value()) | ||
add_cheese(msg.key(), pizza) | ||
|
||
|
||
def add_cheese(order_id, pizza): | ||
pizza['cheese'] = calc_cheese() | ||
cheese_producer.produce('pizza-with-cheese', key=order_id, value=json.dumps(pizza)) | ||
|
||
|
||
def calc_cheese(): | ||
i = random.randint(0, 6) | ||
cheeses = ['extra', 'none', 'three cheese', 'goat cheese', 'extra', 'three cheese', 'goat cheese'] | ||
return cheeses[i] | ||
|
||
|
||
if __name__ == '__main__': | ||
start_service() |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
[tool.poetry] | ||
name = "cheese-service" | ||
version = "0.1.0" | ||
description = "" | ||
authors = ["Dave Klein <[email protected]>"] | ||
|
||
[tool.poetry.dependencies] | ||
python = "^3.9" | ||
confluent-kafka = "^1.8.2" | ||
configparser = "^5.2.0" | ||
|
||
[tool.poetry.dev-dependencies] | ||
|
||
[build-system] | ||
requires = ["poetry-core>=1.0.0"] | ||
build-backend = "poetry.core.masonry.api" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
[kafka_client] | ||
bootstrap.servers=<Kafka server or Confluent Cloud endpoint> | ||
security.protocol=SASL_SSL | ||
sasl.mechanisms=PLAIN | ||
sasl.username=<Confluent Cloud API Key> | ||
sasl.password=<Confluent Cloud API Secret> | ||
auto.offset.reset=earliest | ||
group.id=meats | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
from configparser import ConfigParser | ||
from confluent_kafka import Producer, Consumer | ||
import json | ||
import random | ||
|
||
config_parser = ConfigParser(interpolation=None) | ||
config_file = open('config.properties', 'r') | ||
config_parser.read_file(config_file) | ||
client_config = dict(config_parser['kafka_client']) | ||
|
||
meats_producer = Producer(client_config) | ||
|
||
cheese_consumer = Consumer(client_config) | ||
cheese_consumer.subscribe(['pizza-with-cheese']) | ||
|
||
|
||
def start_service(): | ||
while True: | ||
msg = cheese_consumer.poll(0.1) | ||
if msg is None: | ||
pass | ||
elif msg.error(): | ||
pass | ||
else: | ||
pizza = json.loads(msg.value()) | ||
add_meats(msg.key(), pizza) | ||
|
||
|
||
def add_meats(order_id, pizza): | ||
pizza['meats'] = calc_meats() | ||
meats_producer.produce('pizza-with-meats', key=order_id, value=json.dumps(pizza)) | ||
|
||
|
||
def calc_meats(): | ||
i = random.randint(0, 4) | ||
meats = ['pepperoni', 'sausage', 'ham', 'anchovies', 'salami', 'bacon', 'pepperoni', 'sausage', 'ham', 'anchovies', 'salami', 'bacon'] | ||
selection = [] | ||
if i == 0: | ||
return 'none' | ||
else: | ||
for n in range(i): | ||
selection.append(meats[random.randint(0, 11)]) | ||
return ' & '.join(set(selection)) | ||
|
||
|
||
if __name__ == '__main__': | ||
start_service() |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
[tool.poetry] | ||
name = "meat-service" | ||
version = "0.1.0" | ||
description = "" | ||
authors = ["Dave Klein <[email protected]>"] | ||
|
||
[tool.poetry.dependencies] | ||
python = "^3.9" | ||
confluent-kafka = "^1.8.2" | ||
configparser = "^5.2.0" | ||
|
||
[tool.poetry.dev-dependencies] | ||
|
||
[build-system] | ||
requires = ["poetry-core>=1.0.0"] | ||
build-backend = "poetry.core.masonry.api" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from flask import Flask | ||
import pizza_service | ||
|
||
app = Flask(__name__) | ||
|
||
|
||
@app.route('/order/<count>', methods=['POST']) | ||
def order_pizzas(count): | ||
order_num = pizza_service.order_pizzas(int(count)) | ||
return '{"order_id":"' + order_num + '"}' | ||
|
||
|
||
@app.route('/order/<order_id>', methods=['GET']) | ||
def get_order(order_id): | ||
return pizza_service.get_order(order_id) | ||
|
||
|
||
if __name__ == '__main__': | ||
app.run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[kafka_client] | ||
bootstrap.servers=<Kafka server or Confluent Cloud endpoint> | ||
security.protocol=SASL_SSL | ||
sasl.mechanisms=PLAIN | ||
sasl.username=<Confluent Cloud API Key> | ||
sasl.password=<Confluent Cloud API Secret> | ||
|
||
[consumer] | ||
auto.offset.reset=earliest | ||
group.id=pizza_shop | ||
enable.auto.commit=true | ||
max.poll.interval.ms=3000000 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import json | ||
import uuid | ||
|
||
class Pizza: | ||
def __init__(self): | ||
self.order_id = '' | ||
self.sauce = '' | ||
self.cheese = '' | ||
self.meats = '' | ||
self.veggies = '' | ||
|
||
def toJSON(self): | ||
return json.dumps(self, default=lambda o: o.__dict__, | ||
sort_keys=False, indent=4) | ||
def __str__(self): | ||
return json.dumps(self.__dict__) | ||
|
||
|
||
|
||
class PizzaOrder: | ||
def __init__(self, count): | ||
self.id = str(uuid.uuid4().int) | ||
self.count = count | ||
self.pizzas = [] | ||
|
||
def add_pizza(self, pizza): | ||
self.pizzas.append(pizza) | ||
|
||
def get_pizzas(self): | ||
return self.pizzas | ||
|
||
def __str__(self): | ||
return json.dumps(self.__dict__) | ||
|
||
def toJSON(self): | ||
return json.dumps(self, default=lambda o: o.__dict__, | ||
sort_keys=False, indent=4) |
Oops, something went wrong.