Skip to content

Commit 7fadde9

Browse files
committed
initial commit
1 parent e81bc02 commit 7fadde9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1022
-0
lines changed

grpc-pythons/grpc-apps/.gitignore

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
__pycache__/
2+
*.pyc
3+
*.pyo
4+
venv/
5+
lib/
6+
bin/
7+
db.sqlite3

grpc-pythons/grpc-apps/app.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import grpc
2+
import jobs_pb2
3+
import jobs_pb2_grpc
4+
from concurrent import futures
5+
6+
class JobService(jobs_pb2_grpc.JobServiceServicer):
7+
def AddJob(self, request, context):
8+
job_id = request.job_id
9+
job_status = request.job_status
10+
print(f"Received job with ID {job_id} and status {job_status}")
11+
return jobs_pb2.Job(job_id=job_id, job_status=job_status)
12+
13+
def serve():
14+
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
15+
jobs_pb2_grpc.add_JobServiceServicer_to_server(JobService(), server)
16+
server.add_insecure_port('[::]:50054')
17+
server.start()
18+
print("gRPC server listening on port 50054...")
19+
server.wait_for_termination()
20+
21+
if __name__ == '__main__':
22+
serve()

grpc-pythons/grpc-apps/client.py

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import grpc
2+
import jobs_pb2
3+
import jobs_pb2_grpc
4+
5+
def send_job(job_id, job_status):
6+
with grpc.insecure_channel('localhost:50051') as channel:
7+
stub = jobs_pb2_grpc.JobServiceStub(channel)
8+
job = jobs_pb2.Job(job_id=job_id, job_status=job_status)
9+
response = stub.AddJob(job)
10+
print(f"Server responded with job ID {response.job_id} and status {response.job_status}")
11+
12+
if __name__ == '__main__':
13+
send_job("123", "completed")

grpc-pythons/grpc-apps/jobs.proto

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
syntax = "proto3";
2+
3+
message Job {
4+
string job_id = 1;
5+
string job_status = 2;
6+
}
7+
8+
service JobService {
9+
rpc AddJob(Job) returns (Job);
10+
}

grpc-pythons/grpc-apps/jobs_pb2.py

+27
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2+
"""Client and server classes corresponding to protobuf-defined services."""
3+
import grpc
4+
5+
import jobs_pb2 as jobs__pb2
6+
7+
8+
class JobServiceStub(object):
9+
"""Missing associated documentation comment in .proto file."""
10+
11+
def __init__(self, channel):
12+
"""Constructor.
13+
14+
Args:
15+
channel: A grpc.Channel.
16+
"""
17+
self.AddJob = channel.unary_unary(
18+
'/JobService/AddJob',
19+
request_serializer=jobs__pb2.Job.SerializeToString,
20+
response_deserializer=jobs__pb2.Job.FromString,
21+
)
22+
23+
24+
class JobServiceServicer(object):
25+
"""Missing associated documentation comment in .proto file."""
26+
27+
def AddJob(self, request, context):
28+
"""Missing associated documentation comment in .proto file."""
29+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
30+
context.set_details('Method not implemented!')
31+
raise NotImplementedError('Method not implemented!')
32+
33+
34+
def add_JobServiceServicer_to_server(servicer, server):
35+
rpc_method_handlers = {
36+
'AddJob': grpc.unary_unary_rpc_method_handler(
37+
servicer.AddJob,
38+
request_deserializer=jobs__pb2.Job.FromString,
39+
response_serializer=jobs__pb2.Job.SerializeToString,
40+
),
41+
}
42+
generic_handler = grpc.method_handlers_generic_handler(
43+
'JobService', rpc_method_handlers)
44+
server.add_generic_rpc_handlers((generic_handler,))
45+
46+
47+
# This class is part of an EXPERIMENTAL API.
48+
class JobService(object):
49+
"""Missing associated documentation comment in .proto file."""
50+
51+
@staticmethod
52+
def AddJob(request,
53+
target,
54+
options=(),
55+
channel_credentials=None,
56+
call_credentials=None,
57+
insecure=False,
58+
compression=None,
59+
wait_for_ready=None,
60+
timeout=None,
61+
metadata=None):
62+
return grpc.experimental.unary_unary(request, target, '/JobService/AddJob',
63+
jobs__pb2.Job.SerializeToString,
64+
jobs__pb2.Job.FromString,
65+
options, channel_credentials,
66+
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)

grpc-pythons/grpc-apps/pyvenv.cfg

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
home = /usr/local/opt/[email protected]/bin
2+
implementation = CPython
3+
version_info = 3.9.12.final.0
4+
virtualenv = 20.22.0
5+
include-system-site-packages = false
6+
base-prefix = /usr/local/opt/[email protected]/Frameworks/Python.framework/Versions/3.9
7+
base-exec-prefix = /usr/local/opt/[email protected]/Frameworks/Python.framework/Versions/3.9
8+
base-executable = /usr/local/opt/[email protected]/bin/python3.9
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
grpcio==1.54.0
2+
grpcio-tools==1.54.0
3+
protobuf==4.22.3

load-bal/.gitignore

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
__pycache__/
2+
*.pyc
3+
*.pyo
4+
venv/
5+
lib/
6+
bin/
7+
db.sqlite3

load-bal/app.py

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import grpc
2+
from concurrent import futures
3+
from jobs_pb2_grpc import add_JobServiceServicer_to_server
4+
from services.job_service import JobService
5+
6+
def serve():
7+
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
8+
9+
10+
add_JobServiceServicer_to_server(JobService(), server)
11+
12+
server.add_insecure_port('[::]:50051')
13+
server.start()
14+
15+
print("Load balancer started")
16+
server.wait_for_termination()
17+
18+
if __name__ == '__main__':
19+
serve()

load-bal/jobs.proto

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
syntax = "proto3";
2+
3+
message Job {
4+
string job_id = 1;
5+
string job_status = 2;
6+
}
7+
8+
service JobService {
9+
rpc AddJob(Job) returns (Job);
10+
}

load-bal/jobs_pb2.py

+27
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

load-bal/jobs_pb2_grpc.py

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2+
"""Client and server classes corresponding to protobuf-defined services."""
3+
import grpc
4+
5+
import jobs_pb2 as jobs__pb2
6+
7+
8+
class JobServiceStub(object):
9+
"""Missing associated documentation comment in .proto file."""
10+
11+
def __init__(self, channel):
12+
"""Constructor.
13+
14+
Args:
15+
channel: A grpc.Channel.
16+
"""
17+
self.AddJob = channel.unary_unary(
18+
'/JobService/AddJob',
19+
request_serializer=jobs__pb2.Job.SerializeToString,
20+
response_deserializer=jobs__pb2.Job.FromString,
21+
)
22+
23+
24+
class JobServiceServicer(object):
25+
"""Missing associated documentation comment in .proto file."""
26+
27+
def AddJob(self, request, context):
28+
"""Missing associated documentation comment in .proto file."""
29+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
30+
context.set_details('Method not implemented!')
31+
raise NotImplementedError('Method not implemented!')
32+
33+
34+
def add_JobServiceServicer_to_server(servicer, server):
35+
rpc_method_handlers = {
36+
'AddJob': grpc.unary_unary_rpc_method_handler(
37+
servicer.AddJob,
38+
request_deserializer=jobs__pb2.Job.FromString,
39+
response_serializer=jobs__pb2.Job.SerializeToString,
40+
),
41+
}
42+
generic_handler = grpc.method_handlers_generic_handler(
43+
'JobService', rpc_method_handlers)
44+
server.add_generic_rpc_handlers((generic_handler,))
45+
46+
47+
# This class is part of an EXPERIMENTAL API.
48+
class JobService(object):
49+
"""Missing associated documentation comment in .proto file."""
50+
51+
@staticmethod
52+
def AddJob(request,
53+
target,
54+
options=(),
55+
channel_credentials=None,
56+
call_credentials=None,
57+
insecure=False,
58+
compression=None,
59+
wait_for_ready=None,
60+
timeout=None,
61+
metadata=None):
62+
return grpc.experimental.unary_unary(request, target, '/JobService/AddJob',
63+
jobs__pb2.Job.SerializeToString,
64+
jobs__pb2.Job.FromString,
65+
options, channel_credentials,
66+
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)

load-bal/load_balancer/__init__.py

Whitespace-only changes.
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import hashlib
2+
import bisect
3+
4+
5+
class ConsistentHashLoadBalancer():
6+
def __init__(self, targets):
7+
self.targets = sorted(targets)
8+
self.ring = [self._hash(t) for t in self.targets]
9+
10+
def _hash(self, s):
11+
return int(hashlib.md5(s.encode('utf-8')).hexdigest(), 16)
12+
13+
def _find_target(self, key):
14+
h = self._hash(key)
15+
i = bisect.bisect(self.ring, h)
16+
if i == len(self.ring):
17+
i = 0
18+
return self.targets[i]
19+
20+
def route(self, key):
21+
return self._find_target(key)

load-bal/load_balancer/job_lb.py

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from .consistent_hash import ConsistentHashLoadBalancer
2+
3+
class JobLoadBalancer():
4+
def __init__(self, targets):
5+
self.lb = ConsistentHashLoadBalancer(targets)
6+
7+
def getTarget(self, request, context):
8+
target = self.lb.route(request.job_id)
9+
return target
10+
# return Job(job_id=request.job_id, job_status=request.job_status)

load-bal/pyvenv.cfg

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
home = /usr/local/opt/[email protected]/bin
2+
implementation = CPython
3+
version_info = 3.9.12.final.0
4+
virtualenv = 20.22.0
5+
include-system-site-packages = false
6+
base-prefix = /usr/local/opt/[email protected]/Frameworks/Python.framework/Versions/3.9
7+
base-exec-prefix = /usr/local/opt/[email protected]/Frameworks/Python.framework/Versions/3.9
8+
base-executable = /usr/local/opt/[email protected]/bin/python3.9

load-bal/services/__init__.py

Whitespace-only changes.

load-bal/services/job_service.py

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from jobs_pb2 import Job
2+
from jobs_pb2_grpc import JobServiceServicer
3+
from .send_job import send_job
4+
5+
from load_balancer.job_lb import JobLoadBalancer
6+
7+
targets = ["localhost:50054"]
8+
9+
class JobService(JobServiceServicer):
10+
def __init__(self):
11+
self.lb = JobLoadBalancer(targets)
12+
13+
def AddJob(self, request, context):
14+
target = self.lb.getTarget(request, context)
15+
print(f"Sending request to {target}")
16+
send_job(target, request.job_id, request.job_status)
17+
return Job(job_id=request.job_id, job_status=request.job_status)
18+
19+

load-bal/services/send_job.py

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import jobs_pb2_grpc, jobs_pb2
2+
import grpc
3+
4+
def send_job(target, job_id, job_status):
5+
with grpc.insecure_channel(target) as channel:
6+
stub = jobs_pb2_grpc.JobServiceStub(channel)
7+
job = jobs_pb2.Job(job_id=job_id, job_status=job_status)
8+
response = stub.AddJob(job)
9+
print(f"Server responded with job ID {response.job_id} and status {response.job_status}")

0 commit comments

Comments
 (0)