在使用Redis的python FastAPI应用程序时,我遇到了一个非常奇怪的问题。最后,我试图找出场景2(见下文)失败的原因。
下面我描述了这些场景和一些一般的想法。
下面是一些场景
设想方案1(工作)
方案2(不工作)
FastApi代码
import logging
from typing import Optional, Any
from fastapi import FastAPI, HTTPException, Response, status
from redis_om import Migrator, NotFoundError, get_redis_connection, HashModel, EmbeddedJsonModel, Field, JsonModel
from pydantic import BaseModel, Extra, ValidationError, validator
app = FastAPI(title="FastAPI_Test_App")
log = logging.getLogger(__name__)
log.warning("CONNECTING TO REDIS_HOST: redis-db")
redis_con = get_redis_connection(host="redis-db", decode_responses=True)
class CustomerBase(EmbeddedJsonModel, BaseModel):
first_name: str
last_name: str
email: str
age: int
#CustomerBase.Meta.database = redis_con
log.warning(f"CustomerBase DB connection data: {CustomerBase.Meta.database}") # default database uses localhost
class Customer(JsonModel):
base: CustomerBase
Customer.Meta.database = redis_con # type: ignore
log.warning(f"Customer DB connection data: {Customer.Meta.database}") # this shows redis-db which is CORRECT
@app.get('/customers')
async def all():
customer_pks = Customer.all_pks()
return [format(pk) for pk in customer_pks]
def format(pk: str):
c = Customer.get(pk)
return {
'id': c.pk,
'name': f"{c.first_name} {c.last_name}",
'age': c.age
}
@app.post('/customers')
async def create(customer_base: CustomerBase):
c = Customer(base=customer_base)
#c.Meta.database = redis_con
return c.save()
#return customer.save() # THIS WORKS ALONE...NO OTHER LINES NEED IN THIS FUNCTION
if __name__ == "__main__": # pragma: no cover
log.warning("Running customer app")
# Create a RediSearch index (required for all processes that operate with Tasks)
Migrator().run()
# TODO Move uvicorn to extras_require (if not used in prod)?
import uvicorn
# TODO Add cache in "on event startup"
uvicorn.run("main_REPRODUCE_FAILURE:app", reload=True, host="0.0.0.0", port=5000, log_level="debug")Dockerfile
FROM python:3.9
RUN apt-get update && apt-get -y install iputils-ping
RUN groupadd -g 1000 appuser && \
useradd -rm -s /bin/bash -d /home/appuser -u 1000 -g 1000 appuser
WORKDIR /home/appuser
RUN python -m pip install --upgrade pip
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . .
RUN pip install -vvv -e .
EXPOSE 5000
ENTRYPOINT [ "/bin/bash", "-l", "-c" ]
CMD ["python main_REPRODUCE_FAILURE.py"]码头工
version: '3.8'
services:
redis-db:
image: redislabs/rejson:latest
restart: always
command: redis-server --loglevel debug
volumes:
- fastapi-redis-test:/data
ports:
- "6379:6379"
networks:
- fastapi-redis-test
environment:
fastapi-redis-test_ENV: development
fastapi-redis-test:
build:
context: .
dockerfile: Dockerfile
#command: python main.py
image: fastapi-redis-test
depends_on:
- redis-db
ports:
- "5000:5000"
networks:
- fastapi-redis-test
environment:
REDIS_HOST: redis-db
volumes:
- .:/home/appuser
volumes:
fastapi-redis-test:
driver: local
networks:
fastapi-redis-test:使用localhost运行post时出现异常:5000/docs
fastapi_redis-fastapi-redis-test-1 | CONNECT TO REDIS_HOST: redis-db
fastapi_redis-fastapi-redis-test-1 | CustomerBase DB connection data: Redis<ConnectionPool<Connection<host=localhost,port=6379,db=0>>>
fastapi_redis-fastapi-redis-test-1 | Customer DB connection data: Redis<ConnectionPool<Connection<host=redis-db,port=6379,db=0>>>
fastapi_redis-fastapi-redis-test-1 | CONNECT TO REDIS_HOST: redis-db
fastapi_redis-fastapi-redis-test-1 | CustomerBase DB connection data: Redis<ConnectionPool<Connection<host=localhost,port=6379,db=0>>>
fastapi_redis-fastapi-redis-test-1 | Customer DB connection data: Redis<ConnectionPool<Connection<host=redis-db,port=6379,db=0>>>
fastapi_redis-fastapi-redis-test-1 | INFO: Started server process [14]
fastapi_redis-fastapi-redis-test-1 | INFO: Waiting for application startup.
fastapi_redis-fastapi-redis-test-1 | INFO: Application startup complete.
fastapi_redis-redis-db-1 | 1:M 07 Oct 2022 18:08:40.685 - DB 0: 27 keys (0 volatile) in 32 slots HT.
fastapi_redis-redis-db-1 | 1:M 07 Oct 2022 18:08:40.685 . 1 clients connected (0 replicas), 838736 bytes in use
fastapi_redis-fastapi-redis-test-1 | INFO: 172.21.0.1:58606 - "POST /customers HTTP/1.1" 500 Internal Server Error
fastapi_redis-fastapi-redis-test-1 | ERROR: Exception in ASGI application
fastapi_redis-fastapi-redis-test-1 | Traceback (most recent call last):
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/redis/connection.py", line 611, in connect
fastapi_redis-fastapi-redis-test-1 | sock = self.retry.call_with_retry(
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/redis/retry.py", line 46, in call_with_retry
fastapi_redis-fastapi-redis-test-1 | return do()
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/redis/connection.py", line 612, in <lambda>
fastapi_redis-fastapi-redis-test-1 | lambda: self._connect(), lambda error: self.disconnect(error)
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/redis/connection.py", line 677, in _connect
fastapi_redis-fastapi-redis-test-1 | raise err
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/redis/connection.py", line 665, in _connect
fastapi_redis-fastapi-redis-test-1 | sock.connect(socket_address)
fastapi_redis-fastapi-redis-test-1 | OSError: [Errno 99] Cannot assign requested address
fastapi_redis-fastapi-redis-test-1 |
fastapi_redis-fastapi-redis-test-1 | During handling of the above exception, another exception occurred:
fastapi_redis-fastapi-redis-test-1 |
fastapi_redis-fastapi-redis-test-1 | Traceback (most recent call last):
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/uvicorn/protocols/http/h11_impl.py", line 404, in run_asgi
fastapi_redis-fastapi-redis-test-1 | result = await app( # type: ignore[func-returns-value]
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
fastapi_redis-fastapi-redis-test-1 | return await self.app(scope, receive, send)
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/fastapi/applications.py", line 270, in __call__
fastapi_redis-fastapi-redis-test-1 | await super().__call__(scope, receive, send)
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/starlette/applications.py", line 124, in __call__
fastapi_redis-fastapi-redis-test-1 | await self.middleware_stack(scope, receive, send)
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/starlette/middleware/errors.py", line 184, in __call__
fastapi_redis-fastapi-redis-test-1 | raise exc
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/starlette/middleware/errors.py", line 162, in __call__
fastapi_redis-fastapi-redis-test-1 | await self.app(scope, receive, _send)
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/starlette/middleware/exceptions.py", line 75, in __call__
fastapi_redis-fastapi-redis-test-1 | raise exc
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/starlette/middleware/exceptions.py", line 64, in __call__
fastapi_redis-fastapi-redis-test-1 | await self.app(scope, receive, sender)
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
fastapi_redis-fastapi-redis-test-1 | raise e
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
fastapi_redis-fastapi-redis-test-1 | await self.app(scope, receive, send)
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/starlette/routing.py", line 680, in __call__
fastapi_redis-fastapi-redis-test-1 | await route.handle(scope, receive, send)
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/starlette/routing.py", line 275, in handle
fastapi_redis-fastapi-redis-test-1 | await self.app(scope, receive, send)
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/starlette/routing.py", line 65, in app
fastapi_redis-fastapi-redis-test-1 | response = await func(request)
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/fastapi/routing.py", line 221, in app
fastapi_redis-fastapi-redis-test-1 | solved_result = await solve_dependencies(
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/fastapi/dependencies/utils.py", line 561, in solve_dependencies
fastapi_redis-fastapi-redis-test-1 | ) = await request_body_to_args( # body_params checked above
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/fastapi/dependencies/utils.py", line 696, in request_body_to_args
fastapi_redis-fastapi-redis-test-1 | v_, errors_ = field.validate(value, values, loc=loc)
fastapi_redis-fastapi-redis-test-1 | File "pydantic/fields.py", line 884, in pydantic.fields.ModelField.validate
fastapi_redis-fastapi-redis-test-1 | File "pydantic/fields.py", line 1101, in pydantic.fields.ModelField._validate_singleton
fastapi_redis-fastapi-redis-test-1 | File "pydantic/fields.py", line 1148, in pydantic.fields.ModelField._apply_validators
fastapi_redis-fastapi-redis-test-1 | File "pydantic/class_validators.py", line 318, in pydantic.class_validators._generic_validator_basic.lambda13
fastapi_redis-fastapi-redis-test-1 | File "pydantic/main.py", line 711, in pydantic.main.BaseModel.validate
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/redis_om/model/model.py", line 1469, in __init__
fastapi_redis-fastapi-redis-test-1 | if not has_redis_json(self.db()):
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/redis_om/checks.py", line 17, in has_redis_json
fastapi_redis-fastapi-redis-test-1 | command_exists = check_for_command(conn, "json.set")
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/redis_om/checks.py", line 9, in check_for_command
fastapi_redis-fastapi-redis-test-1 | cmd_info = conn.execute_command("command", "info", cmd)
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/redis/client.py", line 1235, in execute_command
fastapi_redis-fastapi-redis-test-1 | conn = self.connection or pool.get_connection(command_name, **options)
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/redis/connection.py", line 1387, in get_connection
fastapi_redis-fastapi-redis-test-1 | connection.connect()
fastapi_redis-fastapi-redis-test-1 | File "/usr/local/lib/python3.9/site-packages/redis/connection.py", line 617, in connect
fastapi_redis-fastapi-redis-test-1 | raise ConnectionError(self._error_message(e))
fastapi_redis-fastapi-redis-test-1 | redis.exceptions.ConnectionError: Error 99 connecting to localhost:6379. Cannot assign requested address.一些疑难解答的想法:
在redis连接期间,我可以看到stacktrace正确地使用了容器名: redis-db,我发现有趣的是,堆栈跟踪表明,在发布期间,它尝试连接到localhost,而我知道它是坏的b/c,这意味着app试图连接到我的本地机器,而不是redis容器。
看到这个错误后,我试着在CustomerBase和Customer类的Meta类中添加redis-db连接。这样做,我不再有例外。相反,我得到了一个HTTP 422不可处理的实体故障。我想这仅仅是b/c,因为做了一些我打破了正常模型的事情。所以这就让我来看看wonder...why,是使用本地主机而不是redis-db的应用程序吗?OR...is还有其他一些奇怪的问题。我真的在想,正如前面提到的那样,b/c上还有其他的东西,当应用程序不在容器上,而redis在容器上时,earlier...this 失败的安装工作得很好。
我不确定这是否是基于staack跟踪的实际problem...but,这就是我所相信的。我愿意接受所有建议:)
任何帮助都会被指定!
发布于 2022-10-07 19:09:18
这里的问题似乎与redis_om库有关。查看跟踪中的最后一行,我们看到了redis.exceptions.ConnectionError: Error 99 connecting to localhost:6379. Cannot assign requested address.,也就是说,它仍然试图连接到localhost上的redis,尽管您似乎已经将它配置为连接到redis-db。
查看文献资料,有两种方法可以配置库,要么通过设置REDIS_OM_URL环境变量(通过在docker-compose.yml文件中设置REDIS_OM_URL=redis://redis-db:6379来实现),要么通过向模型中添加内部类:
class Customer(JsonModel):
base: CustomerBase
class Meta:
database = redis_con我想,尝试在类声明之后配置连接,就像您在使用Customer.Meta.database = redis_con时所做的那样,是行不通的。
https://stackoverflow.com/questions/73991306
复制相似问题