Add week 2 materials

This commit is contained in:
2026-09-14 14:45:31 +03:00
parent e29c7eb39e
commit 73a65e0855
34 changed files with 1824 additions and 0 deletions
@@ -0,0 +1,9 @@
FROM python:3.12-slim
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "./client.py"]
@@ -0,0 +1,33 @@
# gRPC клиент
В данной директории реализован простой пример клиента на Python, обращающийся к gRPC серверу.
Программа запускает бесконечный цикл, в котором получает текущее значение с сервера и пытается
установить собственное значение, после чего засыпает на случайный промежуток времени.
Процедура повторяется в цикле.
Конфигурация:
- `SERVER_ADDR` — адрес сервера для подключения.
- `VALUE_TO_PUT` — значение, которое будет устанавливать программа.
## protobuf
protubuf спецификация хранится в директории [./proto](./proto/).
protobuf файл сервера должен являться надмножеством с точки зрения API относительно protobuf файла
клиента. Особенно важно сохранять оригинальные tag versions.
```bash
pip3 install grpcio-tools
python3 -m grpc_tools.protoc -I./proto --python_out=. --grpc_python_out=. ./proto/storage.proto
```
## Docker
Сборка образа:
```bash
docker build -t hse-grpc-client .
docker run -d -e SERVER_ADDR=... -e VALUE_TO_PUT=200 hse-grpc-client
```
@@ -0,0 +1,35 @@
import os
import random
import time
import grpc
from google.protobuf.timestamp_pb2 import Timestamp
import storage_pb2
import storage_pb2_grpc
SERVER_ADDR = os.getenv('SERVER_ADDR', 'localhost:51000')
VALUE_TO_PUT = int(os.getenv('VALUE_TO_PUT', '100'))
channel = grpc.insecure_channel(SERVER_ADDR)
stub = storage_pb2_grpc.StorageStub(channel)
while True:
current = stub.GetValue(storage_pb2.GetRequest())
payload = current.value.payload
updated_at = current.value.updated_at.ToDatetime()
if payload != VALUE_TO_PUT:
print(f'Current value: {payload} (updated at {updated_at})')
print(f'Putting {VALUE_TO_PUT}', flush=True)
stub.PutValue(storage_pb2.PutRequest(
value=storage_pb2.Value(payload=VALUE_TO_PUT)
))
delay = random.uniform(1.0, 2.0)
time.sleep(delay)
@@ -0,0 +1,32 @@
syntax = "proto3";
package storage;
option go_package = "hsegrpc/;storagepb";
import "google/protobuf/timestamp.proto";
service Storage {
rpc PutValue(PutRequest) returns (PutResponse);
rpc GetValue(GetRequest) returns (GetResponse);
}
message Value {
uint64 payload = 1;
optional google.protobuf.Timestamp updated_at = 2;
}
message PutRequest {
Value value = 1;
}
message PutResponse {
uint64 value = 1;
}
message GetRequest {
}
message GetResponse {
Value value = 1;
}
@@ -0,0 +1,3 @@
grpcio==1.66.1
grpcio-tools==1.66.1
protobuf==5.28.1
@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# NO CHECKED-IN PROTOBUF GENCODE
# source: storage.proto
# Protobuf Python Version: 5.27.2
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import runtime_version as _runtime_version
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
_runtime_version.ValidateProtobufRuntimeVersion(
_runtime_version.Domain.PUBLIC,
5,
27,
2,
'',
'storage.proto'
)
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rstorage.proto\x12\x07storage\x1a\x1fgoogle/protobuf/timestamp.proto\"\\\n\x05Value\x12\x0f\n\x07payload\x18\x01 \x01(\x04\x12\x33\n\nupdated_at\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x88\x01\x01\x42\r\n\x0b_updated_at\"+\n\nPutRequest\x12\x1d\n\x05value\x18\x01 \x01(\x0b\x32\x0e.storage.Value\"\x1c\n\x0bPutResponse\x12\r\n\x05value\x18\x01 \x01(\x04\"\x0c\n\nGetRequest\",\n\x0bGetResponse\x12\x1d\n\x05value\x18\x01 \x01(\x0b\x32\x0e.storage.Value2w\n\x07Storage\x12\x35\n\x08PutValue\x12\x13.storage.PutRequest\x1a\x14.storage.PutResponse\x12\x35\n\x08GetValue\x12\x13.storage.GetRequest\x1a\x14.storage.GetResponseB\x14Z\x12hsegrpc/;storagepbb\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'storage_pb2', _globals)
if not _descriptor._USE_C_DESCRIPTORS:
_globals['DESCRIPTOR']._loaded_options = None
_globals['DESCRIPTOR']._serialized_options = b'Z\022hsegrpc/;storagepb'
_globals['_VALUE']._serialized_start=59
_globals['_VALUE']._serialized_end=151
_globals['_PUTREQUEST']._serialized_start=153
_globals['_PUTREQUEST']._serialized_end=196
_globals['_PUTRESPONSE']._serialized_start=198
_globals['_PUTRESPONSE']._serialized_end=226
_globals['_GETREQUEST']._serialized_start=228
_globals['_GETREQUEST']._serialized_end=240
_globals['_GETRESPONSE']._serialized_start=242
_globals['_GETRESPONSE']._serialized_end=286
_globals['_STORAGE']._serialized_start=288
_globals['_STORAGE']._serialized_end=407
# @@protoc_insertion_point(module_scope)
@@ -0,0 +1,140 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc
import warnings
import storage_pb2 as storage__pb2
GRPC_GENERATED_VERSION = '1.66.1'
GRPC_VERSION = grpc.__version__
_version_not_supported = False
try:
from grpc._utilities import first_version_is_lower
_version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
except ImportError:
_version_not_supported = True
if _version_not_supported:
raise RuntimeError(
f'The grpc package installed is at version {GRPC_VERSION},'
+ f' but the generated code in storage_pb2_grpc.py depends on'
+ f' grpcio>={GRPC_GENERATED_VERSION}.'
+ f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
+ f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
)
class StorageStub(object):
"""Missing associated documentation comment in .proto file."""
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.PutValue = channel.unary_unary(
'/storage.Storage/PutValue',
request_serializer=storage__pb2.PutRequest.SerializeToString,
response_deserializer=storage__pb2.PutResponse.FromString,
_registered_method=True)
self.GetValue = channel.unary_unary(
'/storage.Storage/GetValue',
request_serializer=storage__pb2.GetRequest.SerializeToString,
response_deserializer=storage__pb2.GetResponse.FromString,
_registered_method=True)
class StorageServicer(object):
"""Missing associated documentation comment in .proto file."""
def PutValue(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def GetValue(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_StorageServicer_to_server(servicer, server):
rpc_method_handlers = {
'PutValue': grpc.unary_unary_rpc_method_handler(
servicer.PutValue,
request_deserializer=storage__pb2.PutRequest.FromString,
response_serializer=storage__pb2.PutResponse.SerializeToString,
),
'GetValue': grpc.unary_unary_rpc_method_handler(
servicer.GetValue,
request_deserializer=storage__pb2.GetRequest.FromString,
response_serializer=storage__pb2.GetResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'storage.Storage', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
server.add_registered_method_handlers('storage.Storage', rpc_method_handlers)
# This class is part of an EXPERIMENTAL API.
class Storage(object):
"""Missing associated documentation comment in .proto file."""
@staticmethod
def PutValue(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(
request,
target,
'/storage.Storage/PutValue',
storage__pb2.PutRequest.SerializeToString,
storage__pb2.PutResponse.FromString,
options,
channel_credentials,
insecure,
call_credentials,
compression,
wait_for_ready,
timeout,
metadata,
_registered_method=True)
@staticmethod
def GetValue(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(
request,
target,
'/storage.Storage/GetValue',
storage__pb2.GetRequest.SerializeToString,
storage__pb2.GetResponse.FromString,
options,
channel_credentials,
insecure,
call_credentials,
compression,
wait_for_ready,
timeout,
metadata,
_registered_method=True)