Error when service registration: TypeError: on_event() takes 2 positional arguments but 3 were given
I am using Docker and docker-compose and cannot register a slave service. What am I doing wrong? Api Gateway (main service) works like a charm but slave service registration fails.
I am not a FastAPI and Python master ;-)
Service main.py:
from picoapi import PicoAPI
from core.config import settings
app = PicoAPI(
title = settings.API_TITLE,
description = settings.API_DESCRIPTION,
version = settings.API_VERSION,
docs_url = settings.API_DOCS_URL,
responses = {404: {"description": "Not found"}},
)
@app.get("/")
async def info():
"""
Info about API documentation.
"""
return { "message": "Welcome in %s microservice, version: %s. For more information go to /docs." % ( app.title, app.version ) }
.env file:
# API config
# ==========
API_TITLE="Example Service"
API_DESCRIPTION="Simple SaaS Boilerplate Example Service"
API_VERSION="0.0.1-alpha"
API_DOCS_URL="/docs"
API_BIND="0.0.0.0"
API_HOST="example-service"
API_PORT="8001"
API_TITLE="Example FastAPI Service"
API_TAGS="slave:microservice"
# microservice registration
# =========================
API_REGISTER_PATH="http://api-gateway:8000/register"
API_HEALTH_PATH="/health"
API_HEALTH_INTERVAL="300"
Dockerfiles:
FROM python:3.8.12
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONBUFFERED 1
ENV PYTHONPATH=/app
RUN mkdir /app
WORKDIR /app/
ADD . /app
RUN pip install --no-cache-dir --upgrade pip
RUN pip install -r requirements.dev.txt --no-cache-dir
EXPOSE 8000
docker-compose.yml
version: '3.8'
services:
api-gateway:
image: api_gateway:dev
build:
context: ./app/api_gateway
dockerfile: Dockerfile
env_file:
- ./app/api_gateway/.env
ports:
- 8000:8000
volumes:
- ${PWD}/app/api_gateway/:/app
command: sh -c "uvicorn main:app --reload --host 0.0.0.0"
networks:
- app
example-service:
image: example-service:dev
build:
context: ./app/custom_services/example_service
dockerfile: Dockerfile
env_file:
- ./app/custom_services/example_service/.env
ports:
- 8001:8000
volumes:
- ${PWD}/app/custom_services/example_service/:/app
depends_on:
- "api-gateway"
command: sh -c "uvicorn main:app --reload --host 0.0.0.0"
networks:
- app
networks:
app:
external: true
Error:
example-service_1 | Traceback (most recent call last):
example-service_1 | File "/usr/local/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
example-service_1 | self.run()
example-service_1 | File "/usr/local/lib/python3.8/multiprocessing/process.py", line 108, in run
example-service_1 | self._target(*self._args, **self._kwargs)
example-service_1 | File "/usr/local/lib/python3.8/site-packages/uvicorn/subprocess.py", line 76, in subprocess_started
example-service_1 | target(sockets=sockets)
example-service_1 | File "/usr/local/lib/python3.8/site-packages/uvicorn/server.py", line 68, in run
example-service_1 | return asyncio.run(self.serve(sockets=sockets))
example-service_1 | File "/usr/local/lib/python3.8/asyncio/runners.py", line 44, in run
example-service_1 | return loop.run_until_complete(main)
example-service_1 | File "/usr/local/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
example-service_1 | return future.result()
example-service_1 | File "/usr/local/lib/python3.8/site-packages/uvicorn/server.py", line 76, in serve
example-service_1 | config.load()
example-service_1 | File "/usr/local/lib/python3.8/site-packages/uvicorn/config.py", line 448, in load
example-service_1 | self.loaded_app = import_from_string(self.app)
example-service_1 | File "/usr/local/lib/python3.8/site-packages/uvicorn/importer.py", line 21, in import_from_string
example-service_1 | module = importlib.import_module(module_str)
example-service_1 | File "/usr/local/lib/python3.8/importlib/__init__.py", line 127, in import_module
example-service_1 | return _bootstrap._gcd_import(name[level:], package, level)
example-service_1 | File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
example-service_1 | File "<frozen importlib._bootstrap>", line 991, in _find_and_load
example-service_1 | File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
example-service_1 | File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
example-service_1 | File "<frozen importlib._bootstrap_external>", line 843, in exec_module
example-service_1 | File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
example-service_1 | File "/app/./main.py", line 4, in <module>
example-service_1 | app = PicoAPI(
example-service_1 | File "/usr/local/lib/python3.8/site-packages/picoapi/api.py", line 85, in __init__
example-service_1 | self.router.on_event("startup", register_uservice)
example-service_1 | TypeError: on_event() takes 2 positional arguments but 3 were given
What I was checking
When I change the slave service from PicoAPI to FastAPI and manually register with CUrl everything looks fine.
curl -X 'GET' \
'http://api-gateway:8000/register' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"name": "Example Service",
"tags": [
"slave:service"
],
"host": "example-service",
"port": 8001,
"metadata": {},
"healthcheck": {
"url": "/health",
"interval": 300
}
}'
result: null
Checking status from gateway:
curl -X 'GET' 'http://api-gateway:8000/services/status' -H 'accept: application/json'
Result:
[{"name":"Example Service","status":"unhealthy"}]
"status": "unhealthy" has no meaning as there is no /health endpoint.
OK, I solved it. When I'm finished I'll send you a PR.
PR https://github.com/schlerp/picoapi/pull/3
Hey, sorry it took me so long to reply. just reviewing your PR now. So this looks like the FastAPI API has changed in a recent version. The general ideas of your PR seem to be on the right track. Unfortunately, this is actually a little more complicated. According to the HTTP spec, the health service registration request needs to be a PUT or POST as its sending a JSON body with information that has semantic meaning to the request (not allowed in a GET).
I have added comments (or am in the process of adding them) to you PR. Would you like to try to submit again making those changes? I'll leave this issue open for discourse until we merge your PR.
Thanks for taking an interest in this project and learning about its internals!
I need something like PicoAPI in my project so I can take care of it. I also want to extend PicoAPI with routing to slave microservices for a more complete solution and fits to my needs, but not only mine, I think :-)