kv-store-grpc
Guidance for building gRPC-based key-value store services in Python. This skill should be used when tasks involve creating gRPC servers, defining protocol buffer schemas, or implementing key-value storage APIs with gRPC. Covers proto file creation, code generation, server implementation, and verification strategies.
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
gRPC Key-Value Store Implementation
Overview
This skill provides procedural knowledge for implementing gRPC-based key-value store services in Python. It covers the complete workflow from proto file definition through server implementation and verification.
Workflow
Step 1: Environment Setup
Install the required gRPC packages with specific versions if provided:
pip install grpcio==<version> grpcio-tools==<version>
If no versions are specified, install the latest:
pip install grpcio grpcio-tools
Verification: Run pip show grpcio grpcio-tools to confirm installation.
Step 2: Define the Protocol Buffer Schema
Create a .proto file defining the service and messages.
Key elements to include:
-
syntax = "proto3";declaration -
packagedeclaration (best practice for larger projects) - Service definition with RPC methods
- Message definitions for requests and responses
Common proto patterns for key-value stores:
syntax = "proto3";
package kvstore;
service KVStore {
rpc SetVal(SetRequest) returns (SetResponse);
rpc GetVal(GetRequest) returns (GetResponse);
}
message SetRequest {
string key = 1;
int32 value = 2;
}
message SetResponse {
bool success = 1;
}
message GetRequest {
string key = 1;
}
message GetResponse {
int32 value = 1;
}
Common pitfall: Forgetting the package declaration - while not strictly required, it prevents naming conflicts in larger projects.
Step 3: Generate Python gRPC Code
Run the protobuf compiler to generate Python code:
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. <service_name>.proto
This generates two files:
-
<service_name>_pb2.py- Message classes -
<service_name>_pb2_grpc.py- Service stubs and base classes
Verification: Confirm both files exist and contain the expected classes by reading them.
Important: Examine the generated *_pb2_grpc.py file to understand:
- The servicer base class to inherit from
- Method signatures to implement
- How to add the servicer to the server
Step 4: Implement the Server
Create a server file that:
- Imports the generated modules
- Implements the servicer class
- Sets up and starts the gRPC server
Key implementation details:
import grpc
from concurrent import futures
import <service_name>_pb2
import <service_name>_pb2_grpc
class KVStoreServicer(<service_name>_pb2_grpc.<ServiceName>Servicer):
def __init__(self):
self.store = {}
def SetVal(self, request, context):
self.store[request.key] = request.value
return <service_name>_pb2.SetResponse(success=True)
def GetVal(self, request, context):
value = self.store.get(request.key, 0) # Default to 0 for missing keys
return <service_name>_pb2.GetResponse(value=value)
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
<service_name>_pb2_grpc.add_<ServiceName>Servicer_to_server(
KVStoreServicer(), server
)
server.add_insecure_port('[::]:50051')
server.start()
print("Server started on port 50051", flush=True) # flush=True is important!
server.wait_for_termination()
if __name__ == '__main__':
serve()
Critical pitfall - Output buffering: When running the server in the background, Python buffers stdout by default. To see output:
- Use
print(..., flush=True)for all print statements - Or run Python with
-uflag:python -u server.py - Or use the
loggingmodule instead of print
Step 5: Start the Server
Run the server in the background:
python server.py &
Or with unbuffered output:
python -u server.py &
Step 6: Verify the Server
Preferred approach: Write and run a test client. This is more reliable than system tools.
Common mistake: Attempting to use system tools like netstat, ss, lsof, or ps to verify the server. These tools may not be available in all environments. Instead, test the server directly with a client.
Test client template:
import grpc
import <service_name>_pb2
import <service_name>_pb2_grpc
def test_kv_store():
channel = grpc.insecure_channel('localhost:50051')
stub = <service_name>_pb2_grpc.<ServiceName>Stub(channel)
# Test SetVal
set_response = stub.SetVal(<service_name>_pb2.SetRequest(key="test_key", value=42))
print(f"SetVal response: success={set_response.success}")
# Test GetVal
get_response = stub.GetVal(<service_name>_pb2.GetRequest(key="test_key"))
print(f"GetVal response: value={get_response.value}")
# Test non-existent key (should return default value)
get_missing = stub.GetVal(<service_name>_pb2.GetRequest(key="missing_key"))
print(f"GetVal missing key: value={get_missing.value}")
if __name__ == '__main__':
test_kv_store()
Comprehensive testing should verify:
- Setting and retrieving values
- Retrieving non-existent keys (verify default behavior)
- Overwriting existing keys
- Multiple different keys
Common Pitfalls
| Pitfall | Solution |
|---|---|
| Print statements not appearing when server runs in background | Use flush=True or run with python -u |
| Trying to use netstat/ss/lsof to verify server | Write a test client instead - more reliable |
| Missing package declaration in proto | Add package <name>; after syntax declaration |
| Not examining generated code before implementing | Read *_pb2_grpc.py to understand the servicer interface |
| Incomplete verification | Test all operations including edge cases |
| No default value for missing keys | Use dict.get(key, default) pattern |
Edge Cases to Consider
- Missing keys: Return a sensible default (often 0 or empty string)
- Empty keys: Consider whether to validate or allow
- Type boundaries: Protobuf enforces int32 bounds automatically
- Connection failures: Client should handle gRPC exceptions
- Server shutdown: Consider implementing graceful shutdown for production
Efficiency Tips
- Verification strategy: Go directly to application-level testing with a client rather than system-level inspection tools
-
Examine generated code: Read the generated
*_pb2_grpc.pyfile before implementing to understand method signatures - Test incrementally: Verify each step works before moving to the next
- Keep test clients: Do not delete test clients - they serve as useful debugging tools
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-02-04
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!