{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "c967f07b",
      "metadata": {
        "id": "c967f07b"
      },
      "source": [
        "# 🚀 Aula Prática de Microserviços no Colab\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "1. Fundamentos de Microserviços\n",
        "1.1 O que são Microserviços?\n",
        "Conceito: \"Microserviços são uma abordagem arquitetônica onde uma aplicação é composta por serviços pequenos, independentes e fracamente acoplados.\"\n",
        "\n",
        "Comparação com Monólito:\n",
        "\n",
        "bash\n",
        "# Arquitetura Monolítica\n",
        "Aplicação = [UI + Lógica Negócio + BD] (Tudo junto)\n",
        "\n",
        "# Arquitetura de Microserviços\n",
        "Aplicação = [\n",
        "    Serviço Usuários,\n",
        "    Serviço Pedidos,\n",
        "    Serviço Pagamentos,\n",
        "    Serviço Catálogo"
      ],
      "metadata": {
        "id": "K9hn8b-8-hh0"
      },
      "id": "K9hn8b-8-hh0"
    },
    {
      "cell_type": "markdown",
      "source": [],
      "metadata": {
        "id": "Kj2cONGsDDhC"
      },
      "id": "Kj2cONGsDDhC"
    },
    {
      "cell_type": "code",
      "source": [
        "\n",
        "from fastapi import FastAPI, HTTPException\n",
        "import uvicorn\n",
        "\n",
        "print(\"✅ Ambiente preparado! Vamos criar microserviços...\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "E-AM-cHwDDQW",
        "outputId": "9f45b302-8091-4d16-9a63-fdefe8dd7ac7"
      },
      "id": "E-AM-cHwDDQW",
      "execution_count": 5,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "✅ Ambiente preparado! Vamos criar microserviços...\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "Vamos criar dois serviços simples que se comunicam: Usuários e Pedidos"
      ],
      "metadata": {
        "id": "0yyD7a8DDSFn"
      },
      "id": "0yyD7a8DDSFn"
    },
    {
      "cell_type": "markdown",
      "source": [],
      "metadata": {
        "id": "sL8FJB8GGrTo"
      },
      "id": "sL8FJB8GGrTo"
    },
    {
      "cell_type": "code",
      "source": [
        "# microservicos_coolab.py\n",
        "from fastapi import FastAPI, HTTPException\n",
        "from fastapi.middleware.cors import CORSMiddleware\n",
        "import uvicorn\n",
        "\n",
        "print(\"🎯 MICROSSERVIÇOS NO COOLAB - TUDO EM UMA PORTA!\")\n",
        "print(\"=\" * 60)\n",
        "\n",
        "app = FastAPI(title=\"Sistema de Microsserviços\")\n",
        "\n",
        "# Configurar CORS para permitir todas as origens\n",
        "app.add_middleware(\n",
        "    CORSMiddleware,\n",
        "    allow_origins=[\"*\"],\n",
        "    allow_credentials=True,\n",
        "    allow_methods=[\"*\"],\n",
        "    allow_headers=[\"*\"],\n",
        ")\n",
        "\n",
        "# ================== BANCO DE DADOS SIMULADO ==================\n",
        "usuarios_db = [\n",
        "    {\"id\": 1, \"nome\": \"Ana Silva\", \"email\": \"ana@email.com\"},\n",
        "    {\"id\": 2, \"nome\": \"João Santos\", \"email\": \"joao@email.com\"},\n",
        "    {\"id\": 3, \"nome\": \"Maria Oliveira\", \"email\": \"maria@email.com\"}\n",
        "]\n",
        "\n",
        "produtos_db = [\n",
        "    {\"id\": 1, \"nome\": \"Notebook Gamer\", \"preco\": 2500.00, \"categoria\": \"informatica\"},\n",
        "    {\"id\": 2, \"nome\": \"Mouse Sem Fio\", \"preco\": 50.00, \"categoria\": \"informatica\"},\n",
        "    {\"id\": 3, \"nome\": \"Cafeteira\", \"preco\": 120.00, \"categoria\": \"casa\"}\n",
        "]\n",
        "\n",
        "pedidos_db = [\n",
        "    {\"id\": 1, \"usuario_id\": 1, \"produto_id\": 1, \"quantidade\": 1, \"status\": \"confirmado\"},\n",
        "    {\"id\": 2, \"usuario_id\": 2, \"produto_id\": 2, \"quantidade\": 2, \"status\": \"pendente\"}\n",
        "]\n",
        "\n",
        "# ================== ROTAS DO SERVICO DE USUÁRIOS ==================\n",
        "@app.get(\"/\")\n",
        "def home():\n",
        "    return {\n",
        "        \"sistema\": \"Microsserviços Educacionais\",\n",
        "        \"status\": \"Online 🚀\",\n",
        "        \"servicos\": {\n",
        "            \"usuarios\": \"/usuarios\",\n",
        "            \"produtos\": \"/produtos\",\n",
        "            \"pedidos\": \"/pedidos\",\n",
        "            \"demo_comunicacao\": \"/pedido-completo/1\"\n",
        "        }\n",
        "    }\n",
        "\n",
        "@app.get(\"/usuarios\")\n",
        "def listar_usuarios():\n",
        "    \"\"\"Serviço de Usuários - Lista todos\"\"\"\n",
        "    return {\n",
        "        \"servico\": \"usuarios\",\n",
        "        \"total\": len(usuarios_db),\n",
        "        \"usuarios\": usuarios_db\n",
        "    }\n",
        "\n",
        "@app.get(\"/usuarios/{usuario_id}\")\n",
        "def buscar_usuario(usuario_id: int):\n",
        "    \"\"\"Serviço de Usuários - Buscar por ID\"\"\"\n",
        "    for usuario in usuarios_db:\n",
        "        if usuario[\"id\"] == usuario_id:\n",
        "            return {\n",
        "                \"servico\": \"usuarios\",\n",
        "                \"usuario\": usuario\n",
        "            }\n",
        "    raise HTTPException(status_code=404, detail=\"Usuário não encontrado\")\n",
        "\n",
        "# ================== ROTAS DO SERVICO DE PRODUTOS ==================\n",
        "@app.get(\"/produtos\")\n",
        "def listar_produtos():\n",
        "    \"\"\"Serviço de Produtos - Lista todos\"\"\"\n",
        "    return {\n",
        "        \"servico\": \"produtos\",\n",
        "        \"total\": len(produtos_db),\n",
        "        \"produtos\": produtos_db\n",
        "    }\n",
        "\n",
        "@app.get(\"/produtos/{produto_id}\")\n",
        "def buscar_produto(produto_id: int):\n",
        "    \"\"\"Serviço de Produtos - Buscar por ID\"\"\"\n",
        "    for produto in produtos_db:\n",
        "        if produto[\"id\"] == produto_id:\n",
        "            return {\n",
        "                \"servico\": \"produtos\",\n",
        "                \"produto\": produto\n",
        "            }\n",
        "    raise HTTPException(status_code=404, detail=\"Produto não encontrado\")\n",
        "\n",
        "@app.get(\"/produtos/categoria/{categoria}\")\n",
        "def produtos_por_categoria(categoria: str):\n",
        "    \"\"\"Serviço de Produtos - Filtrar por categoria\"\"\"\n",
        "    produtos_filtrados = [p for p in produtos_db if p[\"categoria\"] == categoria]\n",
        "    return {\n",
        "        \"servico\": \"produtos\",\n",
        "        \"categoria\": categoria,\n",
        "        \"total\": len(produtos_filtrados),\n",
        "        \"produtos\": produtos_filtrados\n",
        "    }\n",
        "\n",
        "# ================== ROTAS DO SERVICO DE PEDIDOS ==================\n",
        "@app.get(\"/pedidos\")\n",
        "def listar_pedidos():\n",
        "    \"\"\"Serviço de Pedidos - Lista todos\"\"\"\n",
        "    return {\n",
        "        \"servico\": \"pedidos\",\n",
        "        \"total\": len(pedidos_db),\n",
        "        \"pedidos\": pedidos_db\n",
        "    }\n",
        "\n",
        "@app.get(\"/pedidos/{pedido_id}\")\n",
        "def buscar_pedido(pedido_id: int):\n",
        "    \"\"\"Serviço de Pedidos - Buscar por ID\"\"\"\n",
        "    for pedido in pedidos_db:\n",
        "        if pedido[\"id\"] == pedido_id:\n",
        "            return {\n",
        "                \"servico\": \"pedidos\",\n",
        "                \"pedido\": pedido\n",
        "            }\n",
        "    raise HTTPException(status_code=404, detail=\"Pedido não encontrado\")\n",
        "\n",
        "# ================== DEMONSTRAÇÃO: COMUNICAÇÃO ENTRE SERVIÇOS ==================\n",
        "@app.get(\"/pedido-completo/{pedido_id}\")\n",
        "def pedido_completo(pedido_id: int):\n",
        "    \"\"\"\n",
        "    🎯 DEMONSTRAÇÃO DE COMUNICAÇÃO ENTRE MICROSSERVIÇOS\n",
        "\n",
        "    Esta rota simula como microsserviços se comunicariam:\n",
        "    - Busca informações do pedido\n",
        "    - Busca informações do usuário\n",
        "    - Busca informações do produto\n",
        "    - Combina tudo em uma resposta\n",
        "    \"\"\"\n",
        "\n",
        "    # 1. Buscar pedido (simulando chamada ao serviço de pedidos)\n",
        "    pedido = None\n",
        "    for p in pedidos_db:\n",
        "        if p[\"id\"] == pedido_id:\n",
        "            pedido = p\n",
        "            break\n",
        "\n",
        "    if not pedido:\n",
        "        raise HTTPException(status_code=404, detail=\"Pedido não encontrado\")\n",
        "\n",
        "    # 2. Buscar usuário (simulando chamada ao serviço de usuários)\n",
        "    usuario = None\n",
        "    for u in usuarios_db:\n",
        "        if u[\"id\"] == pedido[\"usuario_id\"]:\n",
        "            usuario = u\n",
        "            break\n",
        "\n",
        "    # 3. Buscar produto (simulando chamada ao serviço de produtos)\n",
        "    produto = None\n",
        "    for p in produtos_db:\n",
        "        if p[\"id\"] == pedido[\"produto_id\"]:\n",
        "            produto = p\n",
        "            break\n",
        "\n",
        "    # 4. Montar resposta completa\n",
        "    return {\n",
        "        \"demonstracao\": \"Comunicação entre Microsserviços\",\n",
        "        \"pedido_id\": pedido_id,\n",
        "        \"dados_pedido\": {\n",
        "            \"quantidade\": pedido[\"quantidade\"],\n",
        "            \"status\": pedido[\"status\"]\n",
        "        },\n",
        "        \"dados_usuario\": usuario if usuario else {\"erro\": \"Usuário não encontrado\"},\n",
        "        \"dados_produto\": produto if produto else {\"erro\": \"Produto não encontrado\"},\n",
        "        \"valor_total\": produto[\"preco\"] * pedido[\"quantidade\"] if produto else 0,\n",
        "        \"explicacao\": \"Este endpoint simula como 3 microsserviços diferentes se comunicariam!\"\n",
        "    }\n",
        "\n",
        "@app.get(\"/health\")\n",
        "def health_check():\n",
        "    \"\"\"Verificar status de todos os serviços\"\"\"\n",
        "    return {\n",
        "        \"status\": \"healthy\",\n",
        "        \"servicos\": {\n",
        "            \"usuarios\": \"online\",\n",
        "            \"produtos\": \"online\",\n",
        "            \"pedidos\": \"online\"\n",
        "        }\n",
        "    }\n",
        "\n",
        "if __name__ == \"__main__\":\n",
        "    print(\"🚀 Iniciando todos os microsserviços na porta 8001...\")\n",
        "    print(\"📚 URLs para testar:\")\n",
        "    print(\"   👤 Usuários:     /usuarios\")\n",
        "    print(\"   📦 Produtos:     /produtos\")\n",
        "    print(\"   🛒 Pedidos:      /pedidos\")\n",
        "    print(\"   🎯 Demonstração: /pedido-completo/1\")\n",
        "    print(\"=\" * 60)\n",
        "\n",
        "    uvicorn.run(\n",
        "        app,\n",
        "        host=\"0.0.0.0\",\n",
        "        port=8001, # Changed port to 8001\n",
        "        log_level=\"info\"\n",
        "    )"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        },
        "id": "_xeudtfVH0Zn",
        "outputId": "b77536b5-7f28-46f7-f2ea-91c70d11f76d"
      },
      "id": "_xeudtfVH0Zn",
      "execution_count": 13,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "🎯 MICROSSERVIÇOS NO COOLAB - TUDO EM UMA PORTA!\n",
            "============================================================\n",
            "🚀 Iniciando todos os microsserviços na porta 8001...\n",
            "📚 URLs para testar:\n",
            "   👤 Usuários:     /usuarios\n",
            "   📦 Produtos:     /produtos\n",
            "   🛒 Pedidos:      /pedidos\n",
            "   🎯 Demonstração: /pedido-completo/1\n",
            "============================================================\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "INFO:     Started server process [410]\n",
            "INFO:     Waiting for application startup.\n",
            "INFO:     Application startup complete.\n",
            "ERROR:    [Errno 98] error while attempting to bind on address ('0.0.0.0', 8001): [errno 98] address already in use\n",
            "INFO:     Waiting for application shutdown.\n",
            "INFO:     Application shutdown complete.\n",
            "ERROR:root:Internal Python error in the inspect module.\n",
            "Below is the traceback from this internal error.\n",
            "\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Traceback (most recent call last):\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 164, in startup\n",
            "    server = await loop.create_server(\n",
            "             ^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/lib/python3.12/asyncio/base_events.py\", line 1584, in create_server\n",
            "    raise OSError(err.errno, msg) from None\n",
            "OSError: [Errno 98] error while attempting to bind on address ('0.0.0.0', 8001): [errno 98] address already in use\n",
            "\n",
            "During handling of the above exception, another exception occurred:\n",
            "\n",
            "Traceback (most recent call last):\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/IPython/core/interactiveshell.py\", line 3553, in run_code\n",
            "    exec(code_obj, self.user_global_ns, self.user_ns)\n",
            "  File \"/tmp/ipython-input-982830518.py\", line 197, in <cell line: 0>\n",
            "    uvicorn.run(\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/main.py\", line 580, in run\n",
            "    server.run()\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 67, in run\n",
            "    return asyncio.run(self.serve(sockets=sockets))\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 30, in run\n",
            "    return loop.run_until_complete(task)\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 92, in run_until_complete\n",
            "    self._run_once()\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 133, in _run_once\n",
            "    handle._run()\n",
            "  File \"/usr/lib/python3.12/asyncio/events.py\", line 88, in _run\n",
            "    self._context.run(self._callback, *self._args)\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 396, in __wakeup\n",
            "    self.__step()\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 303, in __step\n",
            "    self.__step_run_and_handle_result(exc)\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 314, in __step_run_and_handle_result\n",
            "    result = coro.send(None)\n",
            "             ^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 71, in serve\n",
            "    await self._serve(sockets)\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 86, in _serve\n",
            "    await self.startup(sockets=sockets)\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 174, in startup\n",
            "    sys.exit(1)\n",
            "SystemExit: 1\n",
            "\n",
            "During handling of the above exception, another exception occurred:\n",
            "\n",
            "Traceback (most recent call last):\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\", line 1101, in get_records\n",
            "    return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\", line 248, in wrapped\n",
            "    return f(*args, **kwargs)\n",
            "           ^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\", line 281, in _fixed_getinnerframes\n",
            "    records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))\n",
            "                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/lib/python3.12/inspect.py\", line 1769, in getinnerframes\n",
            "    traceback_info = getframeinfo(tb, context)\n",
            "                     ^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/lib/python3.12/inspect.py\", line 1701, in getframeinfo\n",
            "    lineno = frame.f_lineno\n",
            "             ^^^^^^^^^^^^^^\n",
            "AttributeError: 'tuple' object has no attribute 'f_lineno'\n"
          ]
        },
        {
          "output_type": "error",
          "ename": "TypeError",
          "evalue": "object of type 'NoneType' has no len()",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mOSError\u001b[0m                                   Traceback (most recent call last)",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\u001b[0m in \u001b[0;36mstartup\u001b[0;34m(self, sockets)\u001b[0m\n\u001b[1;32m    163\u001b[0m             \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 164\u001b[0;31m                 server = await loop.create_server(\n\u001b[0m\u001b[1;32m    165\u001b[0m                     \u001b[0mcreate_protocol\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/lib/python3.12/asyncio/base_events.py\u001b[0m in \u001b[0;36mcreate_server\u001b[0;34m(self, protocol_factory, host, port, family, flags, sock, backlog, ssl, reuse_address, reuse_port, ssl_handshake_timeout, ssl_shutdown_timeout, start_serving)\u001b[0m\n\u001b[1;32m   1583\u001b[0m                             \u001b[0;32mcontinue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1584\u001b[0;31m                         \u001b[0;32mraise\u001b[0m \u001b[0mOSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0merrno\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmsg\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1585\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;31mOSError\u001b[0m: [Errno 98] error while attempting to bind on address ('0.0.0.0', 8001): [errno 98] address already in use",
            "\nDuring handling of the above exception, another exception occurred:\n",
            "\u001b[0;31mSystemExit\u001b[0m                                Traceback (most recent call last)",
            "    \u001b[0;31m[... skipping hidden 1 frame]\u001b[0m\n",
            "\u001b[0;32m/tmp/ipython-input-982830518.py\u001b[0m in \u001b[0;36m<cell line: 0>\u001b[0;34m()\u001b[0m\n\u001b[1;32m    196\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 197\u001b[0;31m     uvicorn.run(\n\u001b[0m\u001b[1;32m    198\u001b[0m         \u001b[0mapp\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/main.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(app, host, port, uds, fd, loop, http, ws, ws_max_size, ws_max_queue, ws_ping_interval, ws_ping_timeout, ws_per_message_deflate, lifespan, interface, reload, reload_dirs, reload_includes, reload_excludes, reload_delay, workers, env_file, log_config, log_level, access_log, proxy_headers, server_header, date_header, forwarded_allow_ips, root_path, limit_concurrency, backlog, limit_max_requests, timeout_keep_alive, timeout_graceful_shutdown, ssl_keyfile, ssl_certfile, ssl_keyfile_password, ssl_version, ssl_cert_reqs, ssl_ca_certs, ssl_ciphers, headers, use_colors, app_dir, factory, h11_max_incomplete_event_size)\u001b[0m\n\u001b[1;32m    579\u001b[0m         \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 580\u001b[0;31m             \u001b[0mserver\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    581\u001b[0m     \u001b[0;32mexcept\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(self, sockets)\u001b[0m\n\u001b[1;32m     66\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconfig\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msetup_event_loop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 67\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0masyncio\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mserve\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msockets\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msockets\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     68\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(main, debug)\u001b[0m\n\u001b[1;32m     29\u001b[0m         \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 30\u001b[0;31m             \u001b[0;32mreturn\u001b[0m \u001b[0mloop\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun_until_complete\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtask\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     31\u001b[0m         \u001b[0;32mfinally\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\u001b[0m in \u001b[0;36mrun_until_complete\u001b[0;34m(self, future)\u001b[0m\n\u001b[1;32m     91\u001b[0m             \u001b[0;32mwhile\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdone\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 92\u001b[0;31m                 \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_run_once\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     93\u001b[0m                 \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_stopping\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\u001b[0m in \u001b[0;36m_run_once\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    132\u001b[0m                 \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 133\u001b[0;31m                     \u001b[0mhandle\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_run\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    134\u001b[0m                 \u001b[0;32mfinally\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/lib/python3.12/asyncio/events.py\u001b[0m in \u001b[0;36m_run\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m     87\u001b[0m         \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 88\u001b[0;31m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_context\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_callback\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_args\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     89\u001b[0m         \u001b[0;32mexcept\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mSystemExit\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/lib/python3.12/asyncio/tasks.py\u001b[0m in \u001b[0;36m__wakeup\u001b[0;34m(self, future)\u001b[0m\n\u001b[1;32m    395\u001b[0m             \u001b[0;31m# that return non-generator iterators from their `__iter__`.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 396\u001b[0;31m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__step\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    397\u001b[0m         \u001b[0mself\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m  \u001b[0;31m# Needed to break cycles when an exception occurs.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/lib/python3.12/asyncio/tasks.py\u001b[0m in \u001b[0;36m__step\u001b[0;34m(self, exc)\u001b[0m\n\u001b[1;32m    302\u001b[0m         \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 303\u001b[0;31m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__step_run_and_handle_result\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mexc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    304\u001b[0m         \u001b[0;32mfinally\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/lib/python3.12/asyncio/tasks.py\u001b[0m in \u001b[0;36m__step_run_and_handle_result\u001b[0;34m(***failed resolving arguments***)\u001b[0m\n\u001b[1;32m    313\u001b[0m                 \u001b[0;31m# don't have `__iter__` and `__next__` methods.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 314\u001b[0;31m                 \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcoro\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    315\u001b[0m             \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\u001b[0m in \u001b[0;36mserve\u001b[0;34m(self, sockets)\u001b[0m\n\u001b[1;32m     70\u001b[0m         \u001b[0;32mwith\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcapture_signals\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 71\u001b[0;31m             \u001b[0;32mawait\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_serve\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msockets\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     72\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\u001b[0m in \u001b[0;36m_serve\u001b[0;34m(self, sockets)\u001b[0m\n\u001b[1;32m     85\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 86\u001b[0;31m         \u001b[0;32mawait\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstartup\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msockets\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msockets\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     87\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshould_exit\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\u001b[0m in \u001b[0;36mstartup\u001b[0;34m(self, sockets)\u001b[0m\n\u001b[1;32m    173\u001b[0m                 \u001b[0;32mawait\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlifespan\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshutdown\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 174\u001b[0;31m                 \u001b[0msys\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    175\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;31mSystemExit\u001b[0m: 1",
            "\nDuring handling of the above exception, another exception occurred:\n",
            "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
            "    \u001b[0;31m[... skipping hidden 1 frame]\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/interactiveshell.py\u001b[0m in \u001b[0;36mshowtraceback\u001b[0;34m(self, exc_tuple, filename, tb_offset, exception_only, running_compiled_code)\u001b[0m\n\u001b[1;32m   2090\u001b[0m                     stb = ['An exception has occurred, use %tb to see '\n\u001b[1;32m   2091\u001b[0m                            'the full traceback.\\n']\n\u001b[0;32m-> 2092\u001b[0;31m                     stb.extend(self.InteractiveTB.get_exception_only(etype,\n\u001b[0m\u001b[1;32m   2093\u001b[0m                                                                      value))\n\u001b[1;32m   2094\u001b[0m                 \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mget_exception_only\u001b[0;34m(self, etype, value)\u001b[0m\n\u001b[1;32m    752\u001b[0m         \u001b[0mvalue\u001b[0m \u001b[0;34m:\u001b[0m \u001b[0mexception\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    753\u001b[0m         \"\"\"\n\u001b[0;32m--> 754\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mListTB\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstructured_traceback\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0metype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    755\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    756\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mshow_exception_only\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0metype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mevalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mstructured_traceback\u001b[0;34m(self, etype, evalue, etb, tb_offset, context)\u001b[0m\n\u001b[1;32m    627\u001b[0m             \u001b[0mchained_exceptions_tb_offset\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    628\u001b[0m             out_list = (\n\u001b[0;32m--> 629\u001b[0;31m                 self.structured_traceback(\n\u001b[0m\u001b[1;32m    630\u001b[0m                     \u001b[0metype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mevalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0metb\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mchained_exc_ids\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    631\u001b[0m                     chained_exceptions_tb_offset, context)\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mstructured_traceback\u001b[0;34m(self, etype, value, tb, tb_offset, number_of_lines_of_context)\u001b[0m\n\u001b[1;32m   1365\u001b[0m         \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1366\u001b[0m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtb\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1367\u001b[0;31m         return FormattedTB.structured_traceback(\n\u001b[0m\u001b[1;32m   1368\u001b[0m             self, etype, value, tb, tb_offset, number_of_lines_of_context)\n\u001b[1;32m   1369\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mstructured_traceback\u001b[0;34m(self, etype, value, tb, tb_offset, number_of_lines_of_context)\u001b[0m\n\u001b[1;32m   1265\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mverbose_modes\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1266\u001b[0m             \u001b[0;31m# Verbose modes need a full traceback\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1267\u001b[0;31m             return VerboseTB.structured_traceback(\n\u001b[0m\u001b[1;32m   1268\u001b[0m                 \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0metype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtb\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtb_offset\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnumber_of_lines_of_context\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1269\u001b[0m             )\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mstructured_traceback\u001b[0;34m(self, etype, evalue, etb, tb_offset, number_of_lines_of_context)\u001b[0m\n\u001b[1;32m   1122\u001b[0m         \u001b[0;34m\"\"\"Return a nice text document describing the traceback.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1123\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1124\u001b[0;31m         formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,\n\u001b[0m\u001b[1;32m   1125\u001b[0m                                                                tb_offset)\n\u001b[1;32m   1126\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mformat_exception_as_a_whole\u001b[0;34m(self, etype, evalue, etb, number_of_lines_of_context, tb_offset)\u001b[0m\n\u001b[1;32m   1080\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1081\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1082\u001b[0;31m         \u001b[0mlast_unique\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrecursion_repeat\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfind_recursion\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0morig_etype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mevalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrecords\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1083\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1084\u001b[0m         \u001b[0mframes\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat_records\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrecords\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlast_unique\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrecursion_repeat\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mfind_recursion\u001b[0;34m(etype, value, records)\u001b[0m\n\u001b[1;32m    380\u001b[0m     \u001b[0;31m# first frame (from in to out) that looks different.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    381\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mis_recursion_error\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0metype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrecords\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 382\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrecords\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    383\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    384\u001b[0m     \u001b[0;31m# Select filename, lineno, func_name to track frames with\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;31mTypeError\u001b[0m: object of type 'NoneType' has no len()"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7def1b99"
      },
      "source": [
        "\n",
        "Criar uma simulação de microserviços em\n",
        " Python."
      ],
      "id": "7def1b99"
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "f6c3d126"
      },
      "source": [
        "## Preparação do ambiente\n",
        "\n",
        "### Obejetivo\n",
        "\n",
        "Garantir que as bibliotecas necessárias (FastAPI, uvicorn, nest_asyncio, etc.) estejam instaladas.\n"
      ],
      "id": "f6c3d126"
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "d42479a1"
      },
      "source": [
        "**Reasoning**:\n",
        "Install the required libraries using pip.\n",
        "\n"
      ],
      "id": "d42479a1"
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "7a7142be",
        "outputId": "1624d106-07d5-4cc3-dad1-06a35bea8367"
      },
      "source": [
        "%pip install fastapi uvicorn nest_asyncio"
      ],
      "id": "7a7142be",
      "execution_count": 14,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Requirement already satisfied: fastapi in /usr/local/lib/python3.12/dist-packages (0.116.2)\n",
            "Requirement already satisfied: uvicorn in /usr/local/lib/python3.12/dist-packages (0.35.0)\n",
            "Requirement already satisfied: nest_asyncio in /usr/local/lib/python3.12/dist-packages (1.6.0)\n",
            "Requirement already satisfied: starlette<0.49.0,>=0.40.0 in /usr/local/lib/python3.12/dist-packages (from fastapi) (0.48.0)\n",
            "Requirement already satisfied: pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4 in /usr/local/lib/python3.12/dist-packages (from fastapi) (2.11.9)\n",
            "Requirement already satisfied: typing-extensions>=4.8.0 in /usr/local/lib/python3.12/dist-packages (from fastapi) (4.15.0)\n",
            "Requirement already satisfied: click>=7.0 in /usr/local/lib/python3.12/dist-packages (from uvicorn) (8.2.1)\n",
            "Requirement already satisfied: h11>=0.8 in /usr/local/lib/python3.12/dist-packages (from uvicorn) (0.16.0)\n",
            "Requirement already satisfied: annotated-types>=0.6.0 in /usr/local/lib/python3.12/dist-packages (from pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4->fastapi) (0.7.0)\n",
            "Requirement already satisfied: pydantic-core==2.33.2 in /usr/local/lib/python3.12/dist-packages (from pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4->fastapi) (2.33.2)\n",
            "Requirement already satisfied: typing-inspection>=0.4.0 in /usr/local/lib/python3.12/dist-packages (from pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4->fastapi) (0.4.1)\n",
            "Requirement already satisfied: anyio<5,>=3.6.2 in /usr/local/lib/python3.12/dist-packages (from starlette<0.49.0,>=0.40.0->fastapi) (4.10.0)\n",
            "Requirement already satisfied: idna>=2.8 in /usr/local/lib/python3.12/dist-packages (from anyio<5,>=3.6.2->starlette<0.49.0,>=0.40.0->fastapi) (3.10)\n",
            "Requirement already satisfied: sniffio>=1.1 in /usr/local/lib/python3.12/dist-packages (from anyio<5,>=3.6.2->starlette<0.49.0,>=0.40.0->fastapi) (1.3.1)\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "/usr/lib/python3.12/pathlib.py:404: RuntimeWarning: coroutine 'Server.serve' was never awaited\n",
            "  parsed = [sys.intern(str(x)) for x in rel.split(sep) if x and x != '.']\n",
            "RuntimeWarning: Enable tracemalloc to get the object allocation traceback\n",
            "ERROR:asyncio:Task exception was never retrieved\n",
            "future: <Task finished name='Task-1' coro=<Server.serve() done, defined at /usr/local/lib/python3.12/dist-packages/uvicorn/server.py:69> exception=KeyboardInterrupt()>\n",
            "Traceback (most recent call last):\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/IPython/core/interactiveshell.py\", line 3553, in run_code\n",
            "    exec(code_obj, self.user_global_ns, self.user_ns)\n",
            "  File \"/tmp/ipython-input-1050662748.py\", line 80, in <cell line: 0>\n",
            "    server.run()\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 67, in run\n",
            "    return asyncio.run(self.serve(sockets=sockets))\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 30, in run\n",
            "    return loop.run_until_complete(task)\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 92, in run_until_complete\n",
            "    self._run_once()\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 133, in _run_once\n",
            "    handle._run()\n",
            "  File \"/usr/lib/python3.12/asyncio/events.py\", line 88, in _run\n",
            "    self._context.run(self._callback, *self._args)\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 396, in __wakeup\n",
            "    self.__step()\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 303, in __step\n",
            "    self.__step_run_and_handle_result(exc)\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 314, in __step_run_and_handle_result\n",
            "    result = coro.send(None)\n",
            "             ^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 70, in serve\n",
            "    with self.capture_signals():\n",
            "         ^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/lib/python3.12/contextlib.py\", line 144, in __exit__\n",
            "    next(self.gen)\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 331, in capture_signals\n",
            "    signal.raise_signal(captured_signal)\n",
            "KeyboardInterrupt\n",
            "ERROR:asyncio:Task exception was never retrieved\n",
            "future: <Task finished name='Task-22' coro=<Server.serve() done, defined at /usr/local/lib/python3.12/dist-packages/uvicorn/server.py:69> exception=SystemExit(1)>\n",
            "Traceback (most recent call last):\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 164, in startup\n",
            "    server = await loop.create_server(\n",
            "             ^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/lib/python3.12/asyncio/base_events.py\", line 1584, in create_server\n",
            "    raise OSError(err.errno, msg) from None\n",
            "OSError: [Errno 98] error while attempting to bind on address ('0.0.0.0', 8000): [errno 98] address already in use\n",
            "\n",
            "During handling of the above exception, another exception occurred:\n",
            "\n",
            "Traceback (most recent call last):\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/IPython/core/interactiveshell.py\", line 3553, in run_code\n",
            "    exec(code_obj, self.user_global_ns, self.user_ns)\n",
            "  File \"/tmp/ipython-input-684182522.py\", line 197, in <cell line: 0>\n",
            "    uvicorn.run(\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/main.py\", line 580, in run\n",
            "    server.run()\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 67, in run\n",
            "    return asyncio.run(self.serve(sockets=sockets))\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 30, in run\n",
            "    return loop.run_until_complete(task)\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 92, in run_until_complete\n",
            "    self._run_once()\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 133, in _run_once\n",
            "    handle._run()\n",
            "  File \"/usr/lib/python3.12/asyncio/events.py\", line 88, in _run\n",
            "    self._context.run(self._callback, *self._args)\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 396, in __wakeup\n",
            "    self.__step()\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 303, in __step\n",
            "    self.__step_run_and_handle_result(exc)\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 314, in __step_run_and_handle_result\n",
            "    result = coro.send(None)\n",
            "             ^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 71, in serve\n",
            "    await self._serve(sockets)\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 86, in _serve\n",
            "    await self.startup(sockets=sockets)\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 174, in startup\n",
            "    sys.exit(1)\n",
            "SystemExit: 1\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "f6bf1f1b"
      },
      "source": [
        "## Definição dos serviços\n",
        "\n",
        "### obejtivo\n",
        "\n",
        "Criar a estrutura básica para cada microsserviço ( Serviço de Usuários, Serviço de Produtos, Serviço de Pedidos) usando FastAPI.\n",
        "\n",
        "\n"
      ],
      "id": "f6bf1f1b"
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1c6ecf5d"
      },
      "source": [
        "# Importante\n",
        "Explique como gerenciar múltiplas portas no FastAPI para simular microsserviços, reestruturando o código existente para demonstrar a comunicação entre eles."
      ],
      "id": "1c6ecf5d"
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "62d687a5"
      },
      "source": [
        "## Explicar o conceito\n",
        "\n",
        "Explicar o conceito de como múltiplos microsserviços rodariam em portas separadas em um ambiente real.\n"
      ],
      "id": "62d687a5"
    },
    {
      "cell_type": "markdown",
      "source": [
        "Em uma arquitetura de microsserviços real, cada serviço (como Usuários, Produtos e Pedidos neste exemplo) seria uma aplicação independente, rodando em sua própria porta ou até mesmo em servidores separados. Isso permite que cada serviço seja desenvolvido, implantado e escalado de forma independente. A comunicação entre esses serviços ocorreria por meio de chamadas de rede, utilizando protocolos como HTTP/REST ou gRPC.\n",
        "\n",
        "Isso contrasta com a simulação inicial que criamos, onde todas as rotas e lógicas de todos os serviços foram definidas dentro de uma única aplicação FastAPI rodando em uma única porta. Embora conveniente para demonstração em um ambiente como o Colab, não reflete a separação fundamental dos microsserviços.\n",
        "\n",
        "O próximo passo será reestruturar o código para simular essa separação conceitual. Mesmo que, no ambiente do Colab, ainda precisemos gerenciar a execução de múltiplos \"serviços\" dentro de um único notebook, a estrutura do código refletirá como eles seriam organizados em um ambiente distribuído."
      ],
      "metadata": {
        "id": "7HBppIZGMpTe"
      },
      "id": "7HBppIZGMpTe"
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "38fad60c"
      },
      "source": [
        "## Reestruturar o código\n",
        "\n",
        "### Subtask:\n",
        "Organizar o código no notebook para que cada \"serviço\" (Usuários, Produtos, Pedidos) seja definido de forma mais modular, como se fosse um arquivo separado.\n"
      ],
      "id": "38fad60c"
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "d5d4f2a6",
        "outputId": "5c42fe00-67af-42d7-c285-4e8efe0218f5"
      },
      "source": [
        "# Serviço de Usuários\n",
        "from fastapi import FastAPI, HTTPException\n",
        "\n",
        "print(\"🛠️ Definindo Serviço de Usuários...\")\n",
        "app_usuarios = FastAPI(title=\"Serviço de Usuários\")\n",
        "\n",
        "# BANCO DE DADOS SIMULADO - Usuários\n",
        "usuarios_db = [\n",
        "    {\"id\": 1, \"nome\": \"Ana Silva\", \"email\": \"ana@email.com\"},\n",
        "    {\"id\": 2, \"nome\": \"João Santos\", \"email\": \"joao@email.com\"},\n",
        "    {\"id\": 3, \"nome\": \"Maria Oliveira\", \"email\": \"maria@email.com\"}\n",
        "]\n",
        "\n",
        "# ROTAS DO SERVIÇO DE USUÁRIOS\n",
        "@app_usuarios.get(\"/usuarios\")\n",
        "def listar_usuarios():\n",
        "    \"\"\"Serviço de Usuários - Lista todos\"\"\"\n",
        "    return {\n",
        "        \"servico\": \"usuarios\",\n",
        "        \"total\": len(usuarios_db),\n",
        "        \"usuarios\": usuarios_db\n",
        "    }\n",
        "\n",
        "@app_usuarios.get(\"/usuarios/{usuario_id}\")\n",
        "def buscar_usuario(usuario_id: int):\n",
        "    \"\"\"Serviço de Usuários - Buscar por ID\"\"\"\n",
        "    for usuario in usuarios_db:\n",
        "        if usuario[\"id\"] == usuario_id:\n",
        "            return {\n",
        "                \"servico\": \"usuarios\",\n",
        "                \"usuario\": usuario\n",
        "            }\n",
        "    raise HTTPException(status_code=404, detail=\"Usuário não encontrado\")\n",
        "\n",
        "print(\"✅ Serviço de Usuários definido!\")"
      ],
      "id": "d5d4f2a6",
      "execution_count": 19,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "🛠️ Definindo Serviço de Usuários...\n",
            "✅ Serviço de Usuários definido!\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "3fd3e0cd",
        "outputId": "7e76246b-73e1-49ce-af31-739f1109ebf3"
      },
      "source": [
        "# Serviço de Produtos\n",
        "from fastapi import FastAPI, HTTPException\n",
        "\n",
        "print(\"🛠️ Definindo Serviço de Produtos...\")\n",
        "app_produtos = FastAPI(title=\"Serviço de Produtos\")\n",
        "\n",
        "# BANCO DE DADOS SIMULADO - Produtos\n",
        "produtos_db = [\n",
        "    {\"id\": 1, \"nome\": \"Notebook Gamer\", \"preco\": 2500.00, \"categoria\": \"informatica\"},\n",
        "    {\"id\": 2, \"nome\": \"Mouse Sem Fio\", \"preco\": 50.00, \"categoria\": \"informatica\"},\n",
        "    {\"id\": 3, \"nome\": \"Cafeteira\", \"preco\": 120.00, \"categoria\": \"casa\"}\n",
        "]\n",
        "\n",
        "# ROTAS DO SERVIÇO DE PRODUTOS\n",
        "@app_produtos.get(\"/produtos\")\n",
        "def listar_produtos():\n",
        "    \"\"\"Serviço de Produtos - Lista todos\"\"\"\n",
        "    return {\n",
        "        \"servico\": \"produtos\",\n",
        "        \"total\": len(produtos_db),\n",
        "        \"produtos\": produtos_db\n",
        "    }\n",
        "\n",
        "@app_produtos.get(\"/produtos/{produto_id}\")\n",
        "def buscar_produto(produto_id: int):\n",
        "    \"\"\"Serviço de Produtos - Buscar por ID\"\"\"\n",
        "    for produto in produtos_db:\n",
        "        if produto[\"id\"] == produto_id:\n",
        "            return {\n",
        "                \"servico\": \"produtos\",\n",
        "                \"produto\": produto\n",
        "            }\n",
        "    raise HTTPException(status_code=404, detail=\"Produto não encontrado\")\n",
        "\n",
        "@app_produtos.get(\"/produtos/categoria/{categoria}\")\n",
        "def produtos_por_categoria(categoria: str):\n",
        "    \"\"\"Serviço de Produtos - Filtrar por categoria\"\"\"\n",
        "    produtos_filtrados = [p for p in produtos_db if p[\"categoria\"] == categoria]\n",
        "    return {\n",
        "        \"servico\": \"produtos\",\n",
        "        \"categoria\": categoria,\n",
        "        \"total\": len(produtos_filtrados),\n",
        "        \"produtos\": produtos_filtrados\n",
        "    }\n",
        "\n",
        "print(\"✅ Serviço de Produtos definido!\")"
      ],
      "id": "3fd3e0cd",
      "execution_count": 20,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "ERROR:asyncio:Task exception was never retrieved\n",
            "future: <Task finished name='Task-34' coro=<Server.serve() done, defined at /usr/local/lib/python3.12/dist-packages/uvicorn/server.py:69> exception=KeyboardInterrupt()>\n",
            "Traceback (most recent call last):\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/main.py\", line 580, in run\n",
            "    server.run()\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 67, in run\n",
            "    return asyncio.run(self.serve(sockets=sockets))\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 30, in run\n",
            "    return loop.run_until_complete(task)\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 92, in run_until_complete\n",
            "    self._run_once()\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 133, in _run_once\n",
            "    handle._run()\n",
            "  File \"/usr/lib/python3.12/asyncio/events.py\", line 88, in _run\n",
            "    self._context.run(self._callback, *self._args)\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 396, in __wakeup\n",
            "    self.__step()\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 303, in __step\n",
            "    self.__step_run_and_handle_result(exc)\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 314, in __step_run_and_handle_result\n",
            "    result = coro.send(None)\n",
            "             ^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 70, in serve\n",
            "    with self.capture_signals():\n",
            "         ^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/lib/python3.12/contextlib.py\", line 144, in __exit__\n",
            "    next(self.gen)\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 331, in capture_signals\n",
            "    signal.raise_signal(captured_signal)\n",
            "KeyboardInterrupt\n",
            "ERROR:    Traceback (most recent call last):\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/starlette/routing.py\", line 701, in lifespan\n",
            "    await receive()\n",
            "GeneratorExit\n",
            "\n",
            "ERROR:asyncio:Task was destroyed but it is pending!\n",
            "task: <Task pending name='Task-35' coro=<LifespanOn.main() done, defined at /usr/local/lib/python3.12/dist-packages/uvicorn/lifespan/on.py:78> wait_for=<Future cancelled>>\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "🛠️ Definindo Serviço de Produtos...\n",
            "✅ Serviço de Produtos definido!\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "_wjy2JyZMk2v",
        "outputId": "4ef00a93-0555-40ce-dce5-393ae6b9889b"
      },
      "source": [
        "# Serviço de Pedidos\n",
        "from fastapi import FastAPI, HTTPException\n",
        "\n",
        "print(\"🛠️ Definindo Serviço de Pedidos...\")\n",
        "app_pedidos = FastAPI(title=\"Serviço de Pedidos\")\n",
        "\n",
        "# BANCO DE DADOS SIMULADO - Pedidos\n",
        "pedidos_db = [\n",
        "    {\"id\": 1, \"usuario_id\": 1, \"produto_id\": 1, \"quantidade\": 1, \"status\": \"confirmado\"},\n",
        "    {\"id\": 2, \"usuario_id\": 2, \"produto_id\": 2, \"quantidade\": 2, \"status\": \"pendente\"}\n",
        "]\n",
        "\n",
        "# ROTAS DO SERVIÇO DE PEDIDOS\n",
        "@app_pedidos.get(\"/pedidos\")\n",
        "def listar_pedidos():\n",
        "    \"\"\"Serviço de Pedidos - Lista todos\"\"\"\n",
        "    return {\n",
        "        \"servico\": \"pedidos\",\n",
        "        \"total\": len(pedidos_db),\n",
        "        \"pedidos\": pedidos_db\n",
        "    }\n",
        "\n",
        "@app_pedidos.get(\"/pedidos/{pedido_id}\")\n",
        "def buscar_pedido(pedido_id: int):\n",
        "    \"\"\"Serviço de Pedidos - Buscar por ID\"\"\"\n",
        "    for pedido in pedidos_db:\n",
        "        if pedido[\"id\"] == pedido_id:\n",
        "            return {\n",
        "                \"servico\": \"pedidos\",\n",
        "                \"pedido\": pedido\n",
        "            }\n",
        "    raise HTTPException(status_code=404, detail=\"Pedido não encontrado\")\n",
        "\n",
        "print(\"✅ Serviço de Pedidos definido!\")"
      ],
      "id": "_wjy2JyZMk2v",
      "execution_count": 21,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "🛠️ Definindo Serviço de Pedidos...\n",
            "✅ Serviço de Pedidos definido!\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "7acea3fc",
        "outputId": "9ca0614b-8ac1-4628-fb8a-c8116a37eade"
      },
      "source": [
        "# Aplicativo Principal / Orquestrador\n",
        "# This app will simulate communication between services and provide entry points\n",
        "from fastapi import FastAPI, HTTPException\n",
        "from fastapi.middleware.cors import CORSMiddleware\n",
        "\n",
        "print(\"🛠️ Definindo Aplicativo Principal / Orquestrador...\")\n",
        "\n",
        "# The main app needs CORS middleware to handle requests from a browser\n",
        "app_main = FastAPI(title=\"Sistema de Microsserviços Orquestrador\")\n",
        "\n",
        "# Configure CORS for the main app\n",
        "app_main.add_middleware(\n",
        "    CORSMiddleware,\n",
        "    allow_origins=[\"*\"],\n",
        "    allow_credentials=True,\n",
        "    allow_methods=[\"*\"],\n",
        "    allow_headers=[\"*\"],\n",
        ")\n",
        "\n",
        "\n",
        "# ================== ROTAS DO APLICATIVO PRINCIPAL ==================\n",
        "@app_main.get(\"/\")\n",
        "def home():\n",
        "    return {\n",
        "        \"sistema\": \"Microsserviços Educacionais\",\n",
        "        \"status\": \"Online 🚀\",\n",
        "        \"servicos_simulados\": {\n",
        "            \"usuarios\": \"interno (simulado)\",\n",
        "            \"produtos\": \"interno (simulado)\",\n",
        "            \"pedidos\": \"interno (simulado)\",\n",
        "            \"demonstracao_comunicacao\": \"/pedido-completo/1\"\n",
        "        },\n",
        "        \"explicacao\": \"Este é o orquestrador, simulando comunicação interna.\"\n",
        "    }\n",
        "\n",
        "@app_main.get(\"/health\")\n",
        "def health_check():\n",
        "    \"\"\"Verificar status de todos os serviços simulados\"\"\"\n",
        "    # In a real scenario, this would check the health of each actual service\n",
        "    return {\n",
        "        \"status\": \"healthy\",\n",
        "        \"servicos_simulados\": {\n",
        "            \"usuarios\": \"simulado_online\",\n",
        "            \"produtos\": \"simulado_online\",\n",
        "            \"pedidos\": \"simulado_online\"\n",
        "        }\n",
        "    }\n",
        "\n",
        "# ================== DEMONSTRAÇÃO: COMUNICAÇÃO ENTRE SERVIÇOS ==================\n",
        "@app_main.get(\"/pedido-completo/{pedido_id}\")\n",
        "def pedido_completo(pedido_id: int):\n",
        "    \"\"\"\n",
        "    🎯 DEMONSTRAÇÃO DE COMUNICAÇÃO ENTRE MICROSSERVIÇOS (Simulada)\n",
        "\n",
        "    Esta rota simula como microsserviços se comunicariam:\n",
        "    - Busca informações do pedido (simulando chamada ao serviço de pedidos)\n",
        "    - Busca informações do usuário (simulando chamada ao serviço de usuários)\n",
        "    - Busca informações do produto (simulando chamada ao serviço de produtos)\n",
        "    - Combina tudo em uma resposta mais detalhada\n",
        "    \"\"\"\n",
        "\n",
        "    #Como se trata de uma simulação dentro de um processo, acessamos diretamente os dados/funções\n",
        "# Em uma arquitetura de microsserviço real, isso seria feito por meio de solicitações HTTP (por exemplo, usando a biblioteca `requests`)\n",
        "\n",
        "    # 1. Buscar pedido (simulando chamada ao serviço de pedidos)\n",
        "    # Access the data directly from the pedidos_db defined in the pedidos service cell\n",
        "    pedido = None\n",
        "    # Assume pedidos_db is accessible (due to notebook environment, normally not the case)\n",
        "    global pedidos_db # Access the global variable defined in the pedidos cell\n",
        "    for p in pedidos_db:\n",
        "        if p[\"id\"] == pedido_id:\n",
        "            pedido = p\n",
        "            break\n",
        "\n",
        "    if not pedido:\n",
        "        raise HTTPException(status_code=404, detail=\"Pedido não encontrado na simulação\")\n",
        "\n",
        "    # 2. Buscar usuário (simulando chamada ao serviço de usuários)\n",
        "    # Access the data directly from the usuarios_db defined in the usuarios service cell\n",
        "    usuario = None\n",
        "    global usuarios_db # Access the global variable defined in the usuarios cell\n",
        "    for u in usuarios_db:\n",
        "        if u[\"id\"] == pedido[\"usuario_id\"]:\n",
        "            usuario = u\n",
        "            break\n",
        "\n",
        "    # 3. Buscar produto (simulando chamada ao serviço de produtos)\n",
        "    # Access the data directly from the produtos_db defined in the produtos service cell\n",
        "    produto = None\n",
        "    global produtos_db # Access the global variable defined in the produtos cell\n",
        "    for p in produtos_db:\n",
        "        if p[\"id\"] == pedido[\"produto_id\"]:\n",
        "            produto = p\n",
        "            break\n",
        "\n",
        "    # 4. Montar resposta completa e mais detalhada\n",
        "    response_data = {\n",
        "        \"demonstracao\": \"Comunicação entre Microsserviços (Simulada)\",\n",
        "        \"pedido_id\": pedido_id,\n",
        "        \"detalhes_pedido\": {\n",
        "            \"quantidade\": pedido[\"quantidade\"],\n",
        "            \"status\": pedido[\"status\"]\n",
        "        },\n",
        "        \"dados_usuario\": usuario if usuario else {\"erro\": \"Usuário não encontrado na simulação\"},\n",
        "        \"dados_produto\": produto if produto else {\"erro\": \"Produto não encontrado na simulação\"},\n",
        "        \"explicacao\": \"Este endpoint simula como 3 microsserviços diferentes se comunicariam internamente.\"\n",
        "    }\n",
        "\n",
        "    # Adicionar valor total se o produto for encontrado\n",
        "    if produto:\n",
        "        response_data[\"valor_total\"] = produto[\"preco\"] * pedido[\"quantidade\"]\n",
        "    else:\n",
        "        response_data[\"valor_total\"] = 0\n",
        "\n",
        "    return response_data\n",
        "\n",
        "print(\"✅ Aplicativo Principal / Orquestrador definido!\")"
      ],
      "id": "7acea3fc",
      "execution_count": 22,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "🛠️ Definindo Aplicativo Principal / Orquestrador...\n",
            "✅ Aplicativo Principal / Orquestrador definido!\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "231428ed"
      },
      "source": [
        "## Explicar o conceito\n",
        "\n",
        "Explicar o conceito de como múltiplos microsserviços rodariam em portas separadas em um ambiente real."
      ],
      "id": "231428ed"
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2a37d200"
      },
      "source": [
        "Em uma arquitetura de microsserviços real, cada serviço (como Usuários, Produtos e Pedidos neste exemplo) seria uma aplicação independente, rodando em sua própria porta ou até mesmo em servidores separados. Isso permite que cada serviço seja desenvolvido, implantado e escalado de forma independente. A comunicação entre esses serviços ocorreria por meio de chamadas de rede, utilizando protocolos como HTTP/REST ou gRPC.\n",
        "\n",
        "Isso contrasta com a simulação inicial que criamos, onde todas as rotas e lógicas de todos os serviços foram definidas dentro de uma única aplicação FastAPI rodando em uma única porta. Embora conveniente para demonstração em um ambiente como o Colab, não reflete a separação fundamental dos microsserviços.\n",
        "\n",
        "O próximo passo será reestruturar o código para simular essa separação conceitual. Mesmo que, no ambiente do Colab, ainda precisemos gerenciar a execução de múltiplos \"serviços\" dentro de um único notebook, a estrutura do código refletirá como eles seriam organizados em um ambiente distribuído."
      ],
      "id": "2a37d200"
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "68fc6945"
      },
      "source": [
        "## Simular inicialização em portas diferentes\n",
        "\n",
        "### Subtask:\n",
        "Mostrar como cada serviço seria configurado para rodar em uma porta específica, mesmo que a execução simultânea no Colab precise de adaptações.\n"
      ],
      "id": "68fc6945"
    },
    {
      "cell_type": "markdown",
      "source": [
        "Como se trata de uma simulação dentro de um processo, acessamos diretamente os dados/funções\n",
        "# Em uma arquitetura de microsserviço real, isso seria feito por meio de solicitações HTTP (por exemplo, usando a biblioteca `requests`)"
      ],
      "metadata": {
        "id": "gW_C9PQDNYBV"
      },
      "id": "gW_C9PQDNYBV"
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        },
        "id": "579209ee",
        "outputId": "8270ea0d-1bba-48b4-e905-0ddb775003d6"
      },
      "source": [
        "import nest_asyncio\n",
        "import uvicorn\n",
        "\n",
        "# Apply nest_asyncio to allow running the asyncio loop within the notebook\n",
        "nest_asyncio.apply()\n",
        "\n",
        "# Note: In Colab, these will run sequentially. Only the first one will actually start\n",
        "# until it's manually interrupted.\n",
        "\n",
        "print(\"🚀 Iniciando Serviço de Usuários na porta 8001...\")\n",
        "uvicorn.run(\n",
        "    app_usuarios,\n",
        "    host=\"0.0.0.0\",\n",
        "    port=8001,\n",
        "    log_level=\"info\"\n",
        ")\n",
        "\n",
        "print(\"🚀 Iniciando Serviço de Pedidos na porta 8002...\")\n",
        "uvicorn.run(\n",
        "    app_pedidos,\n",
        "    host=\"0.0.0.0\",\n",
        "    port=8002,\n",
        "    log_level=\"info\"\n",
        ")\n",
        "\n",
        "print(\"🚀 Iniciando Serviço de Produtos na porta 8003...\")\n",
        "uvicorn.run(\n",
        "    app_produtos,\n",
        "    host=\"0.0.0.0\",\n",
        "    port=8003,\n",
        "    log_level=\"info\"\n",
        ")\n",
        "\n",
        "print(\"✅ Configuração de portas simulada (execução sequencial no Colab).\")"
      ],
      "id": "579209ee",
      "execution_count": 24,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "🚀 Iniciando Serviço de Usuários na porta 8001...\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "INFO:     Started server process [410]\n",
            "INFO:     Waiting for application startup.\n",
            "INFO:     Application startup complete.\n",
            "ERROR:    [Errno 98] error while attempting to bind on address ('0.0.0.0', 8001): [errno 98] address already in use\n",
            "INFO:     Waiting for application shutdown.\n",
            "INFO:     Application shutdown complete.\n",
            "ERROR:root:Internal Python error in the inspect module.\n",
            "Below is the traceback from this internal error.\n",
            "\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Traceback (most recent call last):\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 164, in startup\n",
            "    server = await loop.create_server(\n",
            "             ^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/lib/python3.12/asyncio/base_events.py\", line 1584, in create_server\n",
            "    raise OSError(err.errno, msg) from None\n",
            "OSError: [Errno 98] error while attempting to bind on address ('0.0.0.0', 8001): [errno 98] address already in use\n",
            "\n",
            "During handling of the above exception, another exception occurred:\n",
            "\n",
            "Traceback (most recent call last):\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/IPython/core/interactiveshell.py\", line 3553, in run_code\n",
            "    exec(code_obj, self.user_global_ns, self.user_ns)\n",
            "  File \"/tmp/ipython-input-2338000540.py\", line 11, in <cell line: 0>\n",
            "    uvicorn.run(\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/main.py\", line 580, in run\n",
            "    server.run()\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 67, in run\n",
            "    return asyncio.run(self.serve(sockets=sockets))\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 30, in run\n",
            "    return loop.run_until_complete(task)\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 92, in run_until_complete\n",
            "    self._run_once()\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 133, in _run_once\n",
            "    handle._run()\n",
            "  File \"/usr/lib/python3.12/asyncio/events.py\", line 88, in _run\n",
            "    self._context.run(self._callback, *self._args)\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 396, in __wakeup\n",
            "    self.__step()\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 303, in __step\n",
            "    self.__step_run_and_handle_result(exc)\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 314, in __step_run_and_handle_result\n",
            "    result = coro.send(None)\n",
            "             ^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 71, in serve\n",
            "    await self._serve(sockets)\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 86, in _serve\n",
            "    await self.startup(sockets=sockets)\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 174, in startup\n",
            "    sys.exit(1)\n",
            "SystemExit: 1\n",
            "\n",
            "During handling of the above exception, another exception occurred:\n",
            "\n",
            "Traceback (most recent call last):\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\", line 1101, in get_records\n",
            "    return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\", line 248, in wrapped\n",
            "    return f(*args, **kwargs)\n",
            "           ^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\", line 281, in _fixed_getinnerframes\n",
            "    records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))\n",
            "                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/lib/python3.12/inspect.py\", line 1769, in getinnerframes\n",
            "    traceback_info = getframeinfo(tb, context)\n",
            "                     ^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/lib/python3.12/inspect.py\", line 1701, in getframeinfo\n",
            "    lineno = frame.f_lineno\n",
            "             ^^^^^^^^^^^^^^\n",
            "AttributeError: 'tuple' object has no attribute 'f_lineno'\n"
          ]
        },
        {
          "output_type": "error",
          "ename": "TypeError",
          "evalue": "object of type 'NoneType' has no len()",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mOSError\u001b[0m                                   Traceback (most recent call last)",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\u001b[0m in \u001b[0;36mstartup\u001b[0;34m(self, sockets)\u001b[0m\n\u001b[1;32m    163\u001b[0m             \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 164\u001b[0;31m                 server = await loop.create_server(\n\u001b[0m\u001b[1;32m    165\u001b[0m                     \u001b[0mcreate_protocol\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/lib/python3.12/asyncio/base_events.py\u001b[0m in \u001b[0;36mcreate_server\u001b[0;34m(self, protocol_factory, host, port, family, flags, sock, backlog, ssl, reuse_address, reuse_port, ssl_handshake_timeout, ssl_shutdown_timeout, start_serving)\u001b[0m\n\u001b[1;32m   1583\u001b[0m                             \u001b[0;32mcontinue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1584\u001b[0;31m                         \u001b[0;32mraise\u001b[0m \u001b[0mOSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0merrno\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmsg\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1585\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;31mOSError\u001b[0m: [Errno 98] error while attempting to bind on address ('0.0.0.0', 8001): [errno 98] address already in use",
            "\nDuring handling of the above exception, another exception occurred:\n",
            "\u001b[0;31mSystemExit\u001b[0m                                Traceback (most recent call last)",
            "    \u001b[0;31m[... skipping hidden 1 frame]\u001b[0m\n",
            "\u001b[0;32m/tmp/ipython-input-2338000540.py\u001b[0m in \u001b[0;36m<cell line: 0>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     10\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"🚀 Iniciando Serviço de Usuários na porta 8001...\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m uvicorn.run(\n\u001b[0m\u001b[1;32m     12\u001b[0m     \u001b[0mapp_usuarios\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/main.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(app, host, port, uds, fd, loop, http, ws, ws_max_size, ws_max_queue, ws_ping_interval, ws_ping_timeout, ws_per_message_deflate, lifespan, interface, reload, reload_dirs, reload_includes, reload_excludes, reload_delay, workers, env_file, log_config, log_level, access_log, proxy_headers, server_header, date_header, forwarded_allow_ips, root_path, limit_concurrency, backlog, limit_max_requests, timeout_keep_alive, timeout_graceful_shutdown, ssl_keyfile, ssl_certfile, ssl_keyfile_password, ssl_version, ssl_cert_reqs, ssl_ca_certs, ssl_ciphers, headers, use_colors, app_dir, factory, h11_max_incomplete_event_size)\u001b[0m\n\u001b[1;32m    579\u001b[0m         \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 580\u001b[0;31m             \u001b[0mserver\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    581\u001b[0m     \u001b[0;32mexcept\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(self, sockets)\u001b[0m\n\u001b[1;32m     66\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconfig\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msetup_event_loop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 67\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0masyncio\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mserve\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msockets\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msockets\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     68\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(main, debug)\u001b[0m\n\u001b[1;32m     29\u001b[0m         \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 30\u001b[0;31m             \u001b[0;32mreturn\u001b[0m \u001b[0mloop\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun_until_complete\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtask\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     31\u001b[0m         \u001b[0;32mfinally\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\u001b[0m in \u001b[0;36mrun_until_complete\u001b[0;34m(self, future)\u001b[0m\n\u001b[1;32m     91\u001b[0m             \u001b[0;32mwhile\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdone\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 92\u001b[0;31m                 \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_run_once\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     93\u001b[0m                 \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_stopping\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\u001b[0m in \u001b[0;36m_run_once\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    132\u001b[0m                 \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 133\u001b[0;31m                     \u001b[0mhandle\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_run\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    134\u001b[0m                 \u001b[0;32mfinally\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/lib/python3.12/asyncio/events.py\u001b[0m in \u001b[0;36m_run\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m     87\u001b[0m         \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 88\u001b[0;31m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_context\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_callback\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_args\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     89\u001b[0m         \u001b[0;32mexcept\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mSystemExit\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/lib/python3.12/asyncio/tasks.py\u001b[0m in \u001b[0;36m__wakeup\u001b[0;34m(self, future)\u001b[0m\n\u001b[1;32m    395\u001b[0m             \u001b[0;31m# that return non-generator iterators from their `__iter__`.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 396\u001b[0;31m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__step\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    397\u001b[0m         \u001b[0mself\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m  \u001b[0;31m# Needed to break cycles when an exception occurs.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/lib/python3.12/asyncio/tasks.py\u001b[0m in \u001b[0;36m__step\u001b[0;34m(self, exc)\u001b[0m\n\u001b[1;32m    302\u001b[0m         \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 303\u001b[0;31m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__step_run_and_handle_result\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mexc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    304\u001b[0m         \u001b[0;32mfinally\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/lib/python3.12/asyncio/tasks.py\u001b[0m in \u001b[0;36m__step_run_and_handle_result\u001b[0;34m(***failed resolving arguments***)\u001b[0m\n\u001b[1;32m    313\u001b[0m                 \u001b[0;31m# don't have `__iter__` and `__next__` methods.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 314\u001b[0;31m                 \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcoro\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    315\u001b[0m             \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\u001b[0m in \u001b[0;36mserve\u001b[0;34m(self, sockets)\u001b[0m\n\u001b[1;32m     70\u001b[0m         \u001b[0;32mwith\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcapture_signals\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 71\u001b[0;31m             \u001b[0;32mawait\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_serve\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msockets\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     72\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\u001b[0m in \u001b[0;36m_serve\u001b[0;34m(self, sockets)\u001b[0m\n\u001b[1;32m     85\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 86\u001b[0;31m         \u001b[0;32mawait\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstartup\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msockets\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msockets\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     87\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshould_exit\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\u001b[0m in \u001b[0;36mstartup\u001b[0;34m(self, sockets)\u001b[0m\n\u001b[1;32m    173\u001b[0m                 \u001b[0;32mawait\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlifespan\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshutdown\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 174\u001b[0;31m                 \u001b[0msys\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    175\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;31mSystemExit\u001b[0m: 1",
            "\nDuring handling of the above exception, another exception occurred:\n",
            "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
            "    \u001b[0;31m[... skipping hidden 1 frame]\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/interactiveshell.py\u001b[0m in \u001b[0;36mshowtraceback\u001b[0;34m(self, exc_tuple, filename, tb_offset, exception_only, running_compiled_code)\u001b[0m\n\u001b[1;32m   2090\u001b[0m                     stb = ['An exception has occurred, use %tb to see '\n\u001b[1;32m   2091\u001b[0m                            'the full traceback.\\n']\n\u001b[0;32m-> 2092\u001b[0;31m                     stb.extend(self.InteractiveTB.get_exception_only(etype,\n\u001b[0m\u001b[1;32m   2093\u001b[0m                                                                      value))\n\u001b[1;32m   2094\u001b[0m                 \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mget_exception_only\u001b[0;34m(self, etype, value)\u001b[0m\n\u001b[1;32m    752\u001b[0m         \u001b[0mvalue\u001b[0m \u001b[0;34m:\u001b[0m \u001b[0mexception\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    753\u001b[0m         \"\"\"\n\u001b[0;32m--> 754\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mListTB\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstructured_traceback\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0metype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    755\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    756\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mshow_exception_only\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0metype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mevalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mstructured_traceback\u001b[0;34m(self, etype, evalue, etb, tb_offset, context)\u001b[0m\n\u001b[1;32m    627\u001b[0m             \u001b[0mchained_exceptions_tb_offset\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    628\u001b[0m             out_list = (\n\u001b[0;32m--> 629\u001b[0;31m                 self.structured_traceback(\n\u001b[0m\u001b[1;32m    630\u001b[0m                     \u001b[0metype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mevalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0metb\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mchained_exc_ids\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    631\u001b[0m                     chained_exceptions_tb_offset, context)\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mstructured_traceback\u001b[0;34m(self, etype, value, tb, tb_offset, number_of_lines_of_context)\u001b[0m\n\u001b[1;32m   1365\u001b[0m         \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1366\u001b[0m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtb\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1367\u001b[0;31m         return FormattedTB.structured_traceback(\n\u001b[0m\u001b[1;32m   1368\u001b[0m             self, etype, value, tb, tb_offset, number_of_lines_of_context)\n\u001b[1;32m   1369\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mstructured_traceback\u001b[0;34m(self, etype, value, tb, tb_offset, number_of_lines_of_context)\u001b[0m\n\u001b[1;32m   1265\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mverbose_modes\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1266\u001b[0m             \u001b[0;31m# Verbose modes need a full traceback\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1267\u001b[0;31m             return VerboseTB.structured_traceback(\n\u001b[0m\u001b[1;32m   1268\u001b[0m                 \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0metype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtb\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtb_offset\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnumber_of_lines_of_context\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1269\u001b[0m             )\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mstructured_traceback\u001b[0;34m(self, etype, evalue, etb, tb_offset, number_of_lines_of_context)\u001b[0m\n\u001b[1;32m   1122\u001b[0m         \u001b[0;34m\"\"\"Return a nice text document describing the traceback.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1123\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1124\u001b[0;31m         formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,\n\u001b[0m\u001b[1;32m   1125\u001b[0m                                                                tb_offset)\n\u001b[1;32m   1126\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mformat_exception_as_a_whole\u001b[0;34m(self, etype, evalue, etb, number_of_lines_of_context, tb_offset)\u001b[0m\n\u001b[1;32m   1080\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1081\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1082\u001b[0;31m         \u001b[0mlast_unique\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrecursion_repeat\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfind_recursion\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0morig_etype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mevalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrecords\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1083\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1084\u001b[0m         \u001b[0mframes\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat_records\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrecords\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlast_unique\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrecursion_repeat\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mfind_recursion\u001b[0;34m(etype, value, records)\u001b[0m\n\u001b[1;32m    380\u001b[0m     \u001b[0;31m# first frame (from in to out) that looks different.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    381\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mis_recursion_error\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0metype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrecords\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 382\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrecords\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    383\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    384\u001b[0m     \u001b[0;31m# Select filename, lineno, func_name to track frames with\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;31mTypeError\u001b[0m: object of type 'NoneType' has no len()"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "862400de"
      },
      "source": [
        "## Demonstrar a comunicação inter-serviços\n",
        "\n",
        "### Subtask:\n",
        "Adaptar o endpoint de demonstração (`/pedido-completo`) para simular chamadas HTTP reais entre os serviços rodando em portas diferentes (mesmo que as chamadas sejam \"internas\" dentro do notebook para simplificar).\n"
      ],
      "id": "862400de"
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ef40553f",
        "outputId": "c86eaaf7-c15d-4e67-ed1d-067d403eb39b"
      },
      "source": [
        "import requests\n",
        "\n",
        "# ================== DEMONSTRAÇÃO: COMUNICAÇÃO ENTRE SERVIÇOS (via HTTP Simulado) ==================\n",
        "@app_main.get(\"/pedido-completo/{pedido_id}\")\n",
        "def pedido_completo(pedido_id: int):\n",
        "    \"\"\"\n",
        "    🎯 DEMONSTRAÇÃO DE COMUNICAÇÃO ENTRE MICROSSERVIÇOS (via HTTP Simulado)\n",
        "\n",
        "    Esta rota simula como microsserviços se comunicariam usando chamadas HTTP:\n",
        "    - Busca informações do pedido chamando o Serviço de Pedidos (porta 8002)\n",
        "    - Busca informações do usuário chamando o Serviço de Usuários (porta 8001)\n",
        "    - Busca informações do produto chamando o Serviço de Produtos (porta 8003)\n",
        "    - Combina tudo em uma resposta mais detalhada\n",
        "    \"\"\"\n",
        "\n",
        "    # Simulate HTTP call to the Orders Service (running on port 8002)\n",
        "    orders_url = f\"http://localhost:8002/pedidos/{pedido_id}\"\n",
        "    try:\n",
        "        response_pedido = requests.get(orders_url)\n",
        "        response_pedido.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)\n",
        "        pedido_data = response_pedido.json()\n",
        "        pedido = pedido_data.get(\"pedido\")\n",
        "        if not pedido:\n",
        "             raise HTTPException(status_code=404, detail=\"Pedido não encontrado via Serviço de Pedidos\")\n",
        "    except requests.exceptions.RequestException as e:\n",
        "        raise HTTPException(status_code=500, detail=f\"Erro ao comunicar com Serviço de Pedidos: {e}\")\n",
        "    except HTTPException as e:\n",
        "        raise e # Re-raise the 404 from above\n",
        "\n",
        "\n",
        "    # Simulate HTTP call to the Users Service (running on port 8001)\n",
        "    users_url = f\"http://localhost:8001/usuarios/{pedido['usuario_id']}\"\n",
        "    try:\n",
        "        response_usuario = requests.get(users_url)\n",
        "        response_usuario.raise_for_status()\n",
        "        usuario_data = response_usuario.json()\n",
        "        usuario = usuario_data.get(\"usuario\")\n",
        "        if not usuario:\n",
        "            # This might happen if the user_id in the order doesn't exist in the users service\n",
        "             usuario = {\"erro\": \"Usuário não encontrado no Serviço de Usuários\"}\n",
        "    except requests.exceptions.RequestException as e:\n",
        "         # Handle communication error gracefully, perhaps log and return partial data\n",
        "         print(f\"Warning: Erro ao comunicar com Serviço de Usuários: {e}\")\n",
        "         usuario = {\"erro\": f\"Erro de comunicação com Serviço de Usuários: {e}\"}\n",
        "\n",
        "\n",
        "    # Simulate HTTP call to the Products Service (running on port 8003)\n",
        "    products_url = f\"http://localhost:8003/produtos/{pedido['produto_id']}\"\n",
        "    try:\n",
        "        response_produto = requests.get(products_url)\n",
        "        response_produto.raise_for_status()\n",
        "        produto_data = response_produto.json()\n",
        "        produto = produto_data.get(\"produto\")\n",
        "        if not produto:\n",
        "             # This might happen if the product_id in the order doesn't exist in the products service\n",
        "             produto = {\"erro\": \"Produto não encontrado no Serviço de Produtos\"}\n",
        "    except requests.exceptions.RequestException as e:\n",
        "         # Handle communication error gracefully\n",
        "         print(f\"Warning: Erro ao comunicar com Serviço de Produtos: {e}\")\n",
        "         produto = {\"erro\": f\"Erro de comunicação com Serviço de Produtos: {e}\"}\n",
        "\n",
        "    # 4. Montar resposta completa e mais detalhada\n",
        "    response_data = {\n",
        "        \"demonstracao\": \"Comunicação entre Microsserviços (via HTTP Simulado)\",\n",
        "        \"pedido_id\": pedido_id,\n",
        "        \"detalhes_pedido\": {\n",
        "            \"quantidade\": pedido[\"quantidade\"],\n",
        "            \"status\": pedido[\"status\"]\n",
        "        },\n",
        "        \"dados_usuario\": usuario,\n",
        "        \"dados_produto\": produto,\n",
        "        \"explicacao\": \"Este endpoint simula como 3 microsserviços diferentes se comunicariam via chamadas HTTP!\"\n",
        "    }\n",
        "\n",
        "    # Adicionar valor total se o produto for encontrado and has a price\n",
        "    valor_total = 0\n",
        "    if produto and isinstance(produto, dict) and \"preco\" in produto:\n",
        "        try:\n",
        "            valor_total = produto[\"preco\"] * pedido[\"quantidade\"]\n",
        "        except (TypeError, KeyError):\n",
        "             print(f\"Warning: Não foi possível calcular o valor total para pedido {pedido_id}.\")\n",
        "             valor_total = \"Erro ao calcular valor total\"\n",
        "\n",
        "    response_data[\"valor_total\"] = valor_total\n",
        "\n",
        "\n",
        "    return response_data\n",
        "\n",
        "print(\"✅ Endpoint /pedido-completo modificado para usar chamadas HTTP simuladas!\")"
      ],
      "id": "ef40553f",
      "execution_count": 25,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "✅ Endpoint /pedido-completo modificado para usar chamadas HTTP simuladas!\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7dba8027"
      },
      "source": [
        "## Reestruturar o código\n",
        "\n",
        "### Subtask:\n",
        "Organizar o código no notebook para que cada \"serviço\" (Usuários, Produtos, Pedidos) seja definido de forma mais modular, como se fosse um arquivo separado."
      ],
      "id": "7dba8027"
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "3ea864a0",
        "outputId": "50307a14-36b4-4925-85f6-7b3cbcaa71e3"
      },
      "source": [
        "# Serviço de Usuários\n",
        "from fastapi import FastAPI, HTTPException\n",
        "\n",
        "print(\"🛠️ Definindo Serviço de Usuários...\")\n",
        "app_usuarios = FastAPI(title=\"Serviço de Usuários\")\n",
        "\n",
        "# BANCO DE DADOS SIMULADO - Usuários\n",
        "usuarios_db = [\n",
        "    {\"id\": 1, \"nome\": \"Ana Silva\", \"email\": \"ana@email.com\"},\n",
        "    {\"id\": 2, \"nome\": \"João Santos\", \"email\": \"joao@email.com\"},\n",
        "    {\"id\": 3, \"nome\": \"Maria Oliveira\", \"email\": \"maria@email.com\"}\n",
        "]\n",
        "\n",
        "# ROTAS DO SERVIÇO DE USUÁRIOS\n",
        "@app_usuarios.get(\"/usuarios\")\n",
        "def listar_usuarios():\n",
        "    \"\"\"Serviço de Usuários - Lista todos\"\"\"\n",
        "    return {\n",
        "        \"servico\": \"usuarios\",\n",
        "        \"total\": len(usuarios_db),\n",
        "        \"usuarios\": usuarios_db\n",
        "    }\n",
        "\n",
        "@app_usuarios.get(\"/usuarios/{usuario_id}\")\n",
        "def buscar_usuario(usuario_id: int):\n",
        "    \"\"\"Serviço de Usuários - Buscar por ID\"\"\"\n",
        "    for usuario in usuarios_db:\n",
        "        if usuario[\"id\"] == usuario_id:\n",
        "            return {\n",
        "                \"servico\": \"usuarios\",\n",
        "                \"usuario\": usuario\n",
        "            }\n",
        "    raise HTTPException(status_code=404, detail=\"Usuário não encontrado\")\n",
        "\n",
        "print(\"✅ Serviço de Usuários definido!\")"
      ],
      "id": "3ea864a0",
      "execution_count": 27,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "🛠️ Definindo Serviço de Usuários...\n",
            "✅ Serviço de Usuários definido!\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "c5413ddd"
      },
      "source": [
        "## Demonstrar a comunicação inter-serviços\n",
        "\n",
        "### Subtask:\n",
        "Adaptar o endpoint de demonstração (`/pedido-completo`) para simular chamadas HTTP reais entre os serviços rodando em portas diferentes (mesmo que as chamadas sejam \"internas\" dentro do notebook para simplificar)."
      ],
      "id": "c5413ddd"
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "05786ea1"
      },
      "source": [
        "import requests\n",
        "\n",
        "# ================== DEMONSTRAÇÃO: COMUNICAÇÃO ENTRE SERVIÇOS (via HTTP Simulado) ==================\n",
        "@app_main.get(\"/pedido-completo/{pedido_id}\")\n",
        "def pedido_completo(pedido_id: int):\n",
        "    \"\"\"\n",
        "    🎯 DEMONSTRAÇÃO DE COMUNICAÇÃO ENTRE MICROSSERVIÇOS (via HTTP Simulado)\n",
        "\n",
        "    Esta rota simula como microsserviços se comunicariam usando chamadas HTTP:\n",
        "    - Busca informações do pedido chamando o Serviço de Pedidos (porta 8002)\n",
        "    - Busca informações do usuário chamando o Serviço de Usuários (porta 8001)\n",
        "    - Busca informações do produto chamando o Serviço de Produtos (porta 8003)\n",
        "    - Combina tudo em uma resposta mais detalhada\n",
        "    \"\"\"\n",
        "\n",
        "    # Simulate HTTP call to the Orders Service (running on port 8002)\n",
        "    # NOTE: In this Colab simulation, since services aren't truly running on separate ports\n",
        "    # in parallel within this single process, these requests *won't* actually hit\n",
        "    # running servers. This section primarily demonstrates the *structure* of\n",
        "    # inter-service communication via HTTP calls.\n",
        "    orders_url = f\"http://localhost:8002/pedidos/{pedido_id}\"\n",
        "    try:\n",
        "        # For demonstration purposes in Colab without actual parallel servers,\n",
        "        # we'll directly access the data here as a fallback/simulation.\n",
        "        # In a real microservices setup, this would be a live HTTP request.\n",
        "        # response_pedido = requests.get(orders_url) # Would use in a real scenario\n",
        "        # response_pedido.raise_for_status()\n",
        "        # pedido_data = response_pedido.json()\n",
        "        # pedido = pedido_data.get(\"pedido\")\n",
        "\n",
        "        # *** Colab Simulation Fallback: Direct Data Access ***\n",
        "        global pedidos_db\n",
        "        pedido = None\n",
        "        for p in pedidos_db:\n",
        "            if p[\"id\"] == pedido_id:\n",
        "                pedido = p\n",
        "                break\n",
        "        # *** End Colab Simulation Fallback ***\n",
        "\n",
        "\n",
        "        if not pedido:\n",
        "             raise HTTPException(status_code=404, detail=\"Pedido não encontrado via Serviço de Pedidos (Simulado)\")\n",
        "    except requests.exceptions.RequestException as e:\n",
        "        # In a real scenario, handle communication errors\n",
        "        raise HTTPException(status_code=500, detail=f\"Erro ao comunicar com Serviço de Pedidos (Simulado): {e}\")\n",
        "    except HTTPException as e:\n",
        "        raise e # Re-raise the 404 from above\n",
        "\n",
        "\n",
        "    # Simulate HTTP call to the Users Service (running on port 8001)\n",
        "    users_url = f\"http://localhost:8001/usuarios/{pedido['usuario_id']}\"\n",
        "    try:\n",
        "        # *** Colab Simulation Fallback: Direct Data Access ***\n",
        "        global usuarios_db\n",
        "        usuario = None\n",
        "        for u in usuarios_db:\n",
        "            if u[\"id\"] == pedido[\"usuario_id\"]:\n",
        "                usuario = u\n",
        "                break\n",
        "        # *** End Colab Simulation Fallback ***\n",
        "\n",
        "        if not usuario:\n",
        "            # This might happen if the user_id in the order doesn't exist in the users service\n",
        "             usuario = {\"erro\": \"Usuário não encontrado no Serviço de Usuários (Simulado)\"}\n",
        "    except requests.exceptions.RequestException as e:\n",
        "         # Handle communication error gracefully, perhaps log and return partial data\n",
        "         print(f\"Warning: Erro ao comunicar com Serviço de Usuários (Simulado): {e}\")\n",
        "         usuario = {\"erro\": f\"Erro de comunicação com Serviço de Usuários (Simulado): {e}\"}\n",
        "\n",
        "\n",
        "    # Simulate HTTP call to the Products Service (running on port 8003)\n",
        "    products_url = f\"http://localhost:8003/produtos/{pedido['produto_id']}\"\n",
        "    try:\n",
        "        # *** Colab Simulation Fallback: Direct Data Access ***\n",
        "        global produtos_db\n",
        "        produto = None\n",
        "        for p in produtos_db:\n",
        "            if p[\"id\"] == pedido[\"produto_id\"]:\n",
        "                produto = p\n",
        "                break\n",
        "        # *** End Colab Simulation Fallback ***\n",
        "\n",
        "\n",
        "        if not produto:\n",
        "             # This might happen if the product_id in the order doesn't exist in the products service\n",
        "             produto = {\"erro\": \"Produto não encontrado no Serviço de Produtos (Simulado)\"}\n",
        "    except requests.exceptions.RequestException as e:\n",
        "         # Handle communication error gracefully\n",
        "         print(f\"Warning: Erro ao comunicar com Serviço de Produtos (Simulado): {e}\")\n",
        "         produto = {\"erro\": f\"Erro de comunicação com Serviço de Produtos (Simulado): {e}\"}\n",
        "\n",
        "    # 4. Montar resposta completa e mais detalhada\n",
        "    response_data = {\n",
        "        \"demonstracao\": \"Comunicação entre Microsserviços (via HTTP Simulado)\",\n",
        "        \"pedido_id\": pedido_id,\n",
        "        \"detalhes_pedido\": {\n",
        "            \"quantidade\": pedido[\"quantidade\"],\n",
        "            \"status\": pedido[\"status\"]\n",
        "        },\n",
        "        \"dados_usuario\": usuario,\n",
        "        \"dados_produto\": produto,\n",
        "        \"explicacao\": \"Este endpoint simula como 3 microsserviços diferentes se comunicariam via chamadas HTTP!\"\n",
        "    }\n",
        "\n",
        "    # Adicionar valor total se o produto for encontrado and has a price\n",
        "    valor_total = 0\n",
        "    # Check if produto is a dictionary and has 'preco' key, and if pedido is valid\n",
        "    if isinstance(produto, dict) and \"preco\" in produto and pedido and \"quantidade\" in pedido:\n",
        "        try:\n",
        "            valor_total = produto[\"preco\"] * pedido[\"quantidade\"]\n",
        "        except (TypeError, KeyError):\n",
        "             print(f\"Warning: Não foi possível calcular o valor total para pedido {pedido_id}.\")\n",
        "             valor_total = \"Erro ao calcular valor total\"\n",
        "    elif isinstance(produto, dict) and \"erro\" in produto:\n",
        "         # Product not found, value is 0 or error message\n",
        "         valor_total = \"Produto não encontrado para calcular valor total\"\n",
        "    else:\n",
        "         # pedido or product data missing/invalid structure\n",
        "         print(f\"Warning: Dados de pedido ou produto inválidos para calcular valor total para pedido {pedido_id}.\")\n",
        "         valor_total = \"Dados insuficientes ou inválidos\"\n",
        "\n",
        "\n",
        "    response_data[\"valor_total\"] = valor_total\n",
        "\n",
        "\n",
        "    return response_data"
      ],
      "id": "05786ea1",
      "execution_count": 32,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8f3bad35"
      },
      "source": [
        "## Explicação para alunos\n",
        "\n",
        "### Subtask:\n",
        "Explicação para alunos"
      ],
      "id": "8f3bad35"
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "b9e3b2af"
      },
      "source": [
        "## Explicação Detalhada da Simulação de Microsserviços no Colab\n",
        "\n",
        "Olá! Agora que estruturamos nosso código e simulamos a execução em portas separadas, vamos entender o que realmente fizemos aqui no ambiente do Google Colab e como isso se relaciona com uma arquitetura de microsserviços real.\n",
        "\n",
        "### 1. O Conceito de Microsserviços\n",
        "\n",
        "Como vimos, **microsserviços** são pequenas aplicações independentes. Pense neles como blocos de construção, onde cada bloco faz uma coisa específica (gerenciar usuários, processar pedidos, listar produtos). Em um sistema real:\n",
        "\n",
        "*   Cada microsserviço roda em seu **próprio processo** ou **servidor**.\n",
        "*   Eles se comunicam exclusivamente através da **rede**, geralmente usando protocolos como **HTTP/REST** (como se fosse a internet interna da sua aplicação) ou gRPC.\n",
        "*   São **independentes** para serem desenvolvidos, implantados e escalados (aumentar a capacidade) individualmente.\n",
        "\n",
        "### 2. Como Nossa Simulação no Colab Funciona\n",
        "\n",
        "Nossa estrutura no notebook (com `app_usuarios`, `app_pedidos`, `app_main`) simula essa separação arquitetônica **conceitualmente**:\n",
        "\n",
        "*   Criamos instâncias `FastAPI` separadas para cada \"serviço\", definindo suas rotas e lógica de forma modular. Isso imita a organização de código que você teria se cada serviço estivesse em arquivos ou projetos distintos.\n",
        "*   O `app_main` atua como um **orquestrador** ou uma simulação de **API Gateway**, sendo o ponto de entrada para algumas requisições e orquestrando chamadas entre os \"serviços\" internos.\n",
        "\n",
        "### 3. Limitações da Execução Simultânea no Colab\n",
        "\n",
        "Você deve ter percebido que não conseguimos rodar os três serviços (`app_usuarios`, `app_pedidos`, `app_produtos`) e o `app_main` **ao mesmo tempo** em portas diferentes usando `uvicorn.run()` em uma única célula. Por quê?\n",
        "\n",
        "*   `uvicorn.run()` é uma **função bloqueante**. Quando você a chama, ela assume o controle da execução Python naquela célula e inicia o servidor, esperando por requisições. Ela não retorna até que o servidor seja parado.\n",
        "*   O ambiente de execução do Google Colab geralmente é um **único processo Python**. Você não pode simplesmente iniciar vários servidores web independentes e simultâneos chamando `uvicorn.run()` várias vezes na mesma execução de código.\n",
        "\n",
        "Portanto, embora tenhamos configurado cada `FastAPI` para uma porta diferente, a execução sequencial significa que apenas o primeiro `uvicorn.run()` (se não houver erros de porta) seria iniciado de fato.\n",
        "\n",
        "### 4. Simulação de Comunicação HTTP com `requests`\n",
        "\n",
        "No nosso endpoint `/pedido-completo/{pedido_id}`, adaptamos o código para usar a biblioteca `requests`.\n",
        "\n",
        "*   **Em um ambiente real:** O `app_main` faria requisições HTTP **reais** para os URLs onde os Serviços de Usuários, Pedidos e Produtos estivessem rodando (ex: `http://servico-usuarios:8001/usuarios/123`).\n",
        "*   **Na nossa simulação:** `requests.get(f\"http://localhost:<porta>/...\")` simula essas chamadas HTTP. Mesmo que todos os \"serviços\" estejam definidos no mesmo notebook e não rodando simultaneamente em portas ativas no sentido tradicional do Colab, o uso de `requests` demonstra a **forma** como a comunicação aconteceria. Ele mostra que um serviço (o Orquestrador) pede informações a outro serviço (Usuários, Pedidos, Produtos) usando um endereço de rede simulado (`localhost:<porta>`).\n",
        "\n",
        "### 5. O Que Acontece em uma Implantação Real?\n",
        "\n",
        "Em produção, a história é diferente:\n",
        "\n",
        "*   Cada um dos seus serviços (`app_usuarios`, `app_pedidos`, etc.) seria empacotado e **implantado independentemente**. Isso é frequentemente feito usando **contêineres** (como Docker) e orquestradores (como Kubernetes).\n",
        "*   Cada contêiner rodaria o seu serviço em sua própria porta interna.\n",
        "*   Um **API Gateway** ou **Load Balancer** ficaria na frente, recebendo as requisições externas e as encaminhando para o serviço apropriado. Ele também poderia lidar com autenticação, rate limiting, etc.\n",
        "*   A comunicação entre os serviços internos ainda seria via rede (HTTP, gRPC).\n",
        "\n",
        "### 6. Resumo das Limitações e Aprendizado\n",
        "\n",
        "Nossa abordagem no Colab é uma **simulação simplificada** para fins de aprendizado:\n",
        "\n",
        "*   **Execução Sequencial:** Não rodamos serviços simultaneamente em portas vivas no sentido tradicional.\n",
        "*   **Acesso a Variáveis Globais:** Para a demonstração `/pedido-completo` na versão anterior, acessamos diretamente os dados simulados (global variables). A nova versão com `requests` é melhor, mas ainda é uma simulação dentro do mesmo ambiente. Em um sistema real, não haveria acesso direto a dados de outros serviços.\n",
        "*   **Sem Escalabilidade Real:** Não podemos escalar (aumentar o número de instâncias) de um serviço individualmente.\n",
        "\n",
        "Apesar dessas limitações, a simulação nos ajuda a:\n",
        "\n",
        "*   Entender a **estrutura modular** do código de microsserviços.\n",
        "*   Visualizar como a **comunicação via rede** é o padrão.\n",
        "*   Compreender o papel de um **orquestrador** ou **API Gateway**.\n",
        "\n",
        "### Próximos Passos para Explorar\n",
        "\n",
        "Se você quiser ir além desta simulação, pode tentar:\n",
        "\n",
        "*   Rodar os serviços localmente em seu computador, abrindo **múltiplos terminais** e executando cada serviço separadamente com `uvicorn <nome_arquivo>:<instancia_fastapi> --port <porta>`.\n",
        "*   Explorar **Docker** para empacotar cada serviço em um contêiner e usar `docker-compose` para orquestrá-los e permitir que se comuniquem.\n",
        "\n",
        "Esperamos que esta explicação tenha clareado como nossa simulação se encaixa no mundo real dos microsserviços!"
      ],
      "id": "b9e3b2af"
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "25510161"
      },
      "source": [
        "## Simular inicialização em portas diferentes\n",
        "\n",
        "### Subtask:\n",
        "Mostrar como cada serviço seria configurado para rodar em uma porta específica, mesmo que a execução simultânea no Colab precise de adaptações."
      ],
      "id": "25510161"
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3decaef7"
      },
      "source": [
        "Como se trata de uma simulação dentro de um processo, acessamos diretamente os dados/funções\n",
        "# Em uma arquitetura de microsserviço real, isso seria feito por meio de solicitações HTTP (por exemplo, usando a biblioteca `requests`)"
      ],
      "id": "3decaef7"
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        },
        "id": "97a4e7c3",
        "outputId": "6214381e-0536-4552-d882-55b1a127ea30"
      },
      "source": [
        "import nest_asyncio\n",
        "import uvicorn\n",
        "\n",
        "# Apply nest_asyncio to allow running the asyncio loop within the notebook\n",
        "nest_asyncio.apply()\n",
        "\n",
        "# Note: In Colab, these will run sequentially. Only the first one will actually start\n",
        "# until it's manually interrupted.\n",
        "\n",
        "print(\"🚀 Iniciando Serviço de Usuários na porta 8001...\")\n",
        "uvicorn.run(\n",
        "    app_usuarios,\n",
        "    host=\"0.0.0.0\",\n",
        "    port=8001,\n",
        "    log_level=\"info\"\n",
        ")\n",
        "\n",
        "print(\"🚀 Iniciando Serviço de Pedidos na porta 8002...\")\n",
        "uvicorn.run(\n",
        "    app_pedidos,\n",
        "    host=\"0.0.0.0\",\n",
        "    port=8002,\n",
        "    log_level=\"info\"\n",
        ")\n",
        "\n",
        "print(\"🚀 Iniciando Serviço de Produtos na porta 8003...\")\n",
        "uvicorn.run(\n",
        "    app_produtos,\n",
        "    host=\"0.0.0.0\",\n",
        "    port=8003,\n",
        "    log_level=\"info\"\n",
        ")\n",
        "\n",
        "print(\"✅ Configuração de portas simulada (execução sequencial no Colab).\")"
      ],
      "id": "97a4e7c3",
      "execution_count": 33,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "🚀 Iniciando Serviço de Usuários na porta 8001...\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "INFO:     Started server process [410]\n",
            "INFO:     Waiting for application startup.\n",
            "INFO:     Application startup complete.\n",
            "ERROR:    [Errno 98] error while attempting to bind on address ('0.0.0.0', 8001): [errno 98] address already in use\n",
            "INFO:     Waiting for application shutdown.\n",
            "INFO:     Application shutdown complete.\n",
            "ERROR:root:Internal Python error in the inspect module.\n",
            "Below is the traceback from this internal error.\n",
            "\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Traceback (most recent call last):\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 164, in startup\n",
            "    server = await loop.create_server(\n",
            "             ^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/lib/python3.12/asyncio/base_events.py\", line 1584, in create_server\n",
            "    raise OSError(err.errno, msg) from None\n",
            "OSError: [Errno 98] error while attempting to bind on address ('0.0.0.0', 8001): [errno 98] address already in use\n",
            "\n",
            "During handling of the above exception, another exception occurred:\n",
            "\n",
            "Traceback (most recent call last):\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/IPython/core/interactiveshell.py\", line 3553, in run_code\n",
            "    exec(code_obj, self.user_global_ns, self.user_ns)\n",
            "  File \"/tmp/ipython-input-2338000540.py\", line 11, in <cell line: 0>\n",
            "    uvicorn.run(\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/main.py\", line 580, in run\n",
            "    server.run()\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 67, in run\n",
            "    return asyncio.run(self.serve(sockets=sockets))\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 30, in run\n",
            "    return loop.run_until_complete(task)\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 92, in run_until_complete\n",
            "    self._run_once()\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\", line 133, in _run_once\n",
            "    handle._run()\n",
            "  File \"/usr/lib/python3.12/asyncio/events.py\", line 88, in _run\n",
            "    self._context.run(self._callback, *self._args)\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 396, in __wakeup\n",
            "    self.__step()\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 303, in __step\n",
            "    self.__step_run_and_handle_result(exc)\n",
            "  File \"/usr/lib/python3.12/asyncio/tasks.py\", line 314, in __step_run_and_handle_result\n",
            "    result = coro.send(None)\n",
            "             ^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 71, in serve\n",
            "    await self._serve(sockets)\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 86, in _serve\n",
            "    await self.startup(sockets=sockets)\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\", line 174, in startup\n",
            "    sys.exit(1)\n",
            "SystemExit: 1\n",
            "\n",
            "During handling of the above exception, another exception occurred:\n",
            "\n",
            "Traceback (most recent call last):\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\", line 1101, in get_records\n",
            "    return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\", line 248, in wrapped\n",
            "    return f(*args, **kwargs)\n",
            "           ^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\", line 281, in _fixed_getinnerframes\n",
            "    records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))\n",
            "                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/lib/python3.12/inspect.py\", line 1769, in getinnerframes\n",
            "    traceback_info = getframeinfo(tb, context)\n",
            "                     ^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/lib/python3.12/inspect.py\", line 1701, in getframeinfo\n",
            "    lineno = frame.f_lineno\n",
            "             ^^^^^^^^^^^^^^\n",
            "AttributeError: 'tuple' object has no attribute 'f_lineno'\n"
          ]
        },
        {
          "output_type": "error",
          "ename": "TypeError",
          "evalue": "object of type 'NoneType' has no len()",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mOSError\u001b[0m                                   Traceback (most recent call last)",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\u001b[0m in \u001b[0;36mstartup\u001b[0;34m(self, sockets)\u001b[0m\n\u001b[1;32m    163\u001b[0m             \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 164\u001b[0;31m                 server = await loop.create_server(\n\u001b[0m\u001b[1;32m    165\u001b[0m                     \u001b[0mcreate_protocol\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/lib/python3.12/asyncio/base_events.py\u001b[0m in \u001b[0;36mcreate_server\u001b[0;34m(self, protocol_factory, host, port, family, flags, sock, backlog, ssl, reuse_address, reuse_port, ssl_handshake_timeout, ssl_shutdown_timeout, start_serving)\u001b[0m\n\u001b[1;32m   1583\u001b[0m                             \u001b[0;32mcontinue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1584\u001b[0;31m                         \u001b[0;32mraise\u001b[0m \u001b[0mOSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0merrno\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmsg\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1585\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;31mOSError\u001b[0m: [Errno 98] error while attempting to bind on address ('0.0.0.0', 8001): [errno 98] address already in use",
            "\nDuring handling of the above exception, another exception occurred:\n",
            "\u001b[0;31mSystemExit\u001b[0m                                Traceback (most recent call last)",
            "    \u001b[0;31m[... skipping hidden 1 frame]\u001b[0m\n",
            "\u001b[0;32m/tmp/ipython-input-2338000540.py\u001b[0m in \u001b[0;36m<cell line: 0>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     10\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"🚀 Iniciando Serviço de Usuários na porta 8001...\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m uvicorn.run(\n\u001b[0m\u001b[1;32m     12\u001b[0m     \u001b[0mapp_usuarios\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/main.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(app, host, port, uds, fd, loop, http, ws, ws_max_size, ws_max_queue, ws_ping_interval, ws_ping_timeout, ws_per_message_deflate, lifespan, interface, reload, reload_dirs, reload_includes, reload_excludes, reload_delay, workers, env_file, log_config, log_level, access_log, proxy_headers, server_header, date_header, forwarded_allow_ips, root_path, limit_concurrency, backlog, limit_max_requests, timeout_keep_alive, timeout_graceful_shutdown, ssl_keyfile, ssl_certfile, ssl_keyfile_password, ssl_version, ssl_cert_reqs, ssl_ca_certs, ssl_ciphers, headers, use_colors, app_dir, factory, h11_max_incomplete_event_size)\u001b[0m\n\u001b[1;32m    579\u001b[0m         \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 580\u001b[0;31m             \u001b[0mserver\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    581\u001b[0m     \u001b[0;32mexcept\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(self, sockets)\u001b[0m\n\u001b[1;32m     66\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconfig\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msetup_event_loop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 67\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0masyncio\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mserve\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msockets\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msockets\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     68\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(main, debug)\u001b[0m\n\u001b[1;32m     29\u001b[0m         \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 30\u001b[0;31m             \u001b[0;32mreturn\u001b[0m \u001b[0mloop\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun_until_complete\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtask\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     31\u001b[0m         \u001b[0;32mfinally\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\u001b[0m in \u001b[0;36mrun_until_complete\u001b[0;34m(self, future)\u001b[0m\n\u001b[1;32m     91\u001b[0m             \u001b[0;32mwhile\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdone\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 92\u001b[0;31m                 \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_run_once\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     93\u001b[0m                 \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_stopping\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/nest_asyncio.py\u001b[0m in \u001b[0;36m_run_once\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    132\u001b[0m                 \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 133\u001b[0;31m                     \u001b[0mhandle\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_run\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    134\u001b[0m                 \u001b[0;32mfinally\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/lib/python3.12/asyncio/events.py\u001b[0m in \u001b[0;36m_run\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m     87\u001b[0m         \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 88\u001b[0;31m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_context\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_callback\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_args\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     89\u001b[0m         \u001b[0;32mexcept\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mSystemExit\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/lib/python3.12/asyncio/tasks.py\u001b[0m in \u001b[0;36m__wakeup\u001b[0;34m(self, future)\u001b[0m\n\u001b[1;32m    395\u001b[0m             \u001b[0;31m# that return non-generator iterators from their `__iter__`.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 396\u001b[0;31m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__step\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    397\u001b[0m         \u001b[0mself\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m  \u001b[0;31m# Needed to break cycles when an exception occurs.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/lib/python3.12/asyncio/tasks.py\u001b[0m in \u001b[0;36m__step\u001b[0;34m(self, exc)\u001b[0m\n\u001b[1;32m    302\u001b[0m         \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 303\u001b[0;31m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__step_run_and_handle_result\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mexc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    304\u001b[0m         \u001b[0;32mfinally\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/lib/python3.12/asyncio/tasks.py\u001b[0m in \u001b[0;36m__step_run_and_handle_result\u001b[0;34m(***failed resolving arguments***)\u001b[0m\n\u001b[1;32m    313\u001b[0m                 \u001b[0;31m# don't have `__iter__` and `__next__` methods.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 314\u001b[0;31m                 \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcoro\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    315\u001b[0m             \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\u001b[0m in \u001b[0;36mserve\u001b[0;34m(self, sockets)\u001b[0m\n\u001b[1;32m     70\u001b[0m         \u001b[0;32mwith\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcapture_signals\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 71\u001b[0;31m             \u001b[0;32mawait\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_serve\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msockets\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     72\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\u001b[0m in \u001b[0;36m_serve\u001b[0;34m(self, sockets)\u001b[0m\n\u001b[1;32m     85\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 86\u001b[0;31m         \u001b[0;32mawait\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstartup\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msockets\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msockets\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     87\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshould_exit\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/uvicorn/server.py\u001b[0m in \u001b[0;36mstartup\u001b[0;34m(self, sockets)\u001b[0m\n\u001b[1;32m    173\u001b[0m                 \u001b[0;32mawait\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlifespan\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshutdown\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 174\u001b[0;31m                 \u001b[0msys\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    175\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;31mSystemExit\u001b[0m: 1",
            "\nDuring handling of the above exception, another exception occurred:\n",
            "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
            "    \u001b[0;31m[... skipping hidden 1 frame]\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/interactiveshell.py\u001b[0m in \u001b[0;36mshowtraceback\u001b[0;34m(self, exc_tuple, filename, tb_offset, exception_only, running_compiled_code)\u001b[0m\n\u001b[1;32m   2090\u001b[0m                     stb = ['An exception has occurred, use %tb to see '\n\u001b[1;32m   2091\u001b[0m                            'the full traceback.\\n']\n\u001b[0;32m-> 2092\u001b[0;31m                     stb.extend(self.InteractiveTB.get_exception_only(etype,\n\u001b[0m\u001b[1;32m   2093\u001b[0m                                                                      value))\n\u001b[1;32m   2094\u001b[0m                 \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mget_exception_only\u001b[0;34m(self, etype, value)\u001b[0m\n\u001b[1;32m    752\u001b[0m         \u001b[0mvalue\u001b[0m \u001b[0;34m:\u001b[0m \u001b[0mexception\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    753\u001b[0m         \"\"\"\n\u001b[0;32m--> 754\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mListTB\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstructured_traceback\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0metype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    755\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    756\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mshow_exception_only\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0metype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mevalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mstructured_traceback\u001b[0;34m(self, etype, evalue, etb, tb_offset, context)\u001b[0m\n\u001b[1;32m    627\u001b[0m             \u001b[0mchained_exceptions_tb_offset\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    628\u001b[0m             out_list = (\n\u001b[0;32m--> 629\u001b[0;31m                 self.structured_traceback(\n\u001b[0m\u001b[1;32m    630\u001b[0m                     \u001b[0metype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mevalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0metb\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mchained_exc_ids\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    631\u001b[0m                     chained_exceptions_tb_offset, context)\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mstructured_traceback\u001b[0;34m(self, etype, value, tb, tb_offset, number_of_lines_of_context)\u001b[0m\n\u001b[1;32m   1365\u001b[0m         \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1366\u001b[0m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtb\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1367\u001b[0;31m         return FormattedTB.structured_traceback(\n\u001b[0m\u001b[1;32m   1368\u001b[0m             self, etype, value, tb, tb_offset, number_of_lines_of_context)\n\u001b[1;32m   1369\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mstructured_traceback\u001b[0;34m(self, etype, value, tb, tb_offset, number_of_lines_of_context)\u001b[0m\n\u001b[1;32m   1265\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mverbose_modes\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1266\u001b[0m             \u001b[0;31m# Verbose modes need a full traceback\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1267\u001b[0;31m             return VerboseTB.structured_traceback(\n\u001b[0m\u001b[1;32m   1268\u001b[0m                 \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0metype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtb\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtb_offset\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnumber_of_lines_of_context\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1269\u001b[0m             )\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mstructured_traceback\u001b[0;34m(self, etype, evalue, etb, tb_offset, number_of_lines_of_context)\u001b[0m\n\u001b[1;32m   1122\u001b[0m         \u001b[0;34m\"\"\"Return a nice text document describing the traceback.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1123\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1124\u001b[0;31m         formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,\n\u001b[0m\u001b[1;32m   1125\u001b[0m                                                                tb_offset)\n\u001b[1;32m   1126\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mformat_exception_as_a_whole\u001b[0;34m(self, etype, evalue, etb, number_of_lines_of_context, tb_offset)\u001b[0m\n\u001b[1;32m   1080\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1081\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1082\u001b[0;31m         \u001b[0mlast_unique\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrecursion_repeat\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfind_recursion\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0morig_etype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mevalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrecords\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1083\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1084\u001b[0m         \u001b[0mframes\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat_records\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrecords\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlast_unique\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrecursion_repeat\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.12/dist-packages/IPython/core/ultratb.py\u001b[0m in \u001b[0;36mfind_recursion\u001b[0;34m(etype, value, records)\u001b[0m\n\u001b[1;32m    380\u001b[0m     \u001b[0;31m# first frame (from in to out) that looks different.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    381\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mis_recursion_error\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0metype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrecords\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 382\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrecords\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    383\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    384\u001b[0m     \u001b[0;31m# Select filename, lineno, func_name to track frames with\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;31mTypeError\u001b[0m: object of type 'NoneType' has no len()"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4900947a"
      },
      "source": [
        "**Comandos para Rodar os Serviços Localmente**\n",
        "\n",
        "Assumindo que você salvou o código de cada serviço e do orquestrador em arquivos `.py` separados:\n",
        "\n",
        "*   `users_service.py` (contém `app_usuarios`)\n",
        "*   `products_service.py` (contém `app_produtos`)\n",
        "*   `orders_service.py` (contém `app_pedidos`)\n",
        "*   `main_app.py` (contém `app_main`)\n",
        "\n",
        "Abra **quatro terminais diferentes** na pasta onde esses arquivos estão salvos e execute um comando por terminal:\n",
        "\n",
        "1.  **Serviço de Usuários (Porta 8001):**"
      ],
      "id": "4900947a"
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "d0646bfa"
      },
      "source": [
        "    uvicorn products_service:app_produtos --reload --port 8003"
      ],
      "id": "d0646bfa",
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "6ee96c62"
      },
      "source": [
        "    uvicorn orders_service:app_pedidos --reload --port 8002"
      ],
      "id": "6ee96c62",
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "eb990b3b"
      },
      "source": [
        "    uvicorn main_app:app_main --reload --port 8000"
      ],
      "id": "eb990b3b",
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "53e7913e",
        "outputId": "fcdb77cc-e738-4311-8931-e51a838ae7e2"
      },
      "source": [
        "# Serviço de Produtos\n",
        "from fastapi import FastAPI, HTTPException\n",
        "\n",
        "print(\"🛠️ Definindo Serviço de Produtos...\")\n",
        "app_produtos = FastAPI(title=\"Serviço de Produtos\")\n",
        "\n",
        "# BANCO DE DADOS SIMULADO - Produtos\n",
        "produtos_db = [\n",
        "    {\"id\": 1, \"nome\": \"Notebook Gamer\", \"preco\": 2500.00, \"categoria\": \"informatica\"},\n",
        "    {\"id\": 2, \"nome\": \"Mouse Sem Fio\", \"preco\": 50.00, \"categoria\": \"informatica\"},\n",
        "    {\"id\": 3, \"nome\": \"Cafeteira\", \"preco\": 120.00, \"categoria\": \"casa\"}\n",
        "]\n",
        "\n",
        "# ROTAS DO SERVIÇO DE PRODUTOS\n",
        "@app_produtos.get(\"/produtos\")\n",
        "def listar_produtos():\n",
        "    \"\"\"Serviço de Produtos - Lista todos\"\"\"\n",
        "    return {\n",
        "        \"servico\": \"produtos\",\n",
        "        \"total\": len(produtos_db),\n",
        "        \"produtos\": produtos_db\n",
        "    }\n",
        "\n",
        "@app_produtos.get(\"/produtos/{produto_id}\")\n",
        "def buscar_produto(produto_id: int):\n",
        "    \"\"\"Serviço de Produtos - Buscar por ID\"\"\"\n",
        "    for produto in produtos_db:\n",
        "        if produto[\"id\"] == produto_id:\n",
        "            return {\n",
        "                \"servico\": \"produtos\",\n",
        "                \"produto\": produto\n",
        "            }\n",
        "    raise HTTPException(status_code=404, detail=\"Produto não encontrado\")\n",
        "\n",
        "@app_produtos.get(\"/produtos/categoria/{categoria}\")\n",
        "def produtos_por_categoria(categoria: str):\n",
        "    \"\"\"Serviço de Produtos - Filtrar por categoria\"\"\"\n",
        "    produtos_filtrados = [p for p in produtos_db if p[\"categoria\"] == categoria]\n",
        "    return {\n",
        "        \"servico\": \"produtos\",\n",
        "        \"categoria\": categoria,\n",
        "        \"total\": len(produtos_filtrados),\n",
        "        \"produtos\": produtos_filtrados\n",
        "    }\n",
        "\n",
        "print(\"✅ Serviço de Produtos definido!\")"
      ],
      "id": "53e7913e",
      "execution_count": 28,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "🛠️ Definindo Serviço de Produtos...\n",
            "✅ Serviço de Produtos definido!\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "223062dc",
        "outputId": "fcf86b01-05b7-48cb-d483-24426d98f04e"
      },
      "source": [
        "# Serviço de Pedidos\n",
        "from fastapi import FastAPI, HTTPException\n",
        "\n",
        "print(\"🛠️ Definindo Serviço de Pedidos...\")\n",
        "app_pedidos = FastAPI(title=\"Serviço de Pedidos\")\n",
        "\n",
        "# BANCO DE DADOS SIMULADO - Pedidos\n",
        "pedidos_db = [\n",
        "    {\"id\": 1, \"usuario_id\": 1, \"produto_id\": 1, \"quantidade\": 1, \"status\": \"confirmado\"},\n",
        "    {\"id\": 2, \"usuario_id\": 2, \"produto_id\": 2, \"quantidade\": 2, \"status\": \"pendente\"}\n",
        "]\n",
        "\n",
        "# ROTAS DO SERVIÇO DE PEDIDOS\n",
        "@app_pedidos.get(\"/pedidos\")\n",
        "def listar_pedidos():\n",
        "    \"\"\"Serviço de Pedidos - Lista todos\"\"\"\n",
        "    return {\n",
        "        \"servico\": \"pedidos\",\n",
        "        \"total\": len(pedidos_db),\n",
        "        \"pedidos\": pedidos_db\n",
        "    }\n",
        "\n",
        "@app_pedidos.get(\"/pedidos/{pedido_id}\")\n",
        "def buscar_pedido(pedido_id: int):\n",
        "    \"\"\"Serviço de Pedidos - Buscar por ID\"\"\"\n",
        "    for pedido in pedidos_db:\n",
        "        if pedido[\"id\"] == pedido_id:\n",
        "            return {\n",
        "                \"servico\": \"pedidos\",\n",
        "                \"pedido\": pedido\n",
        "            }\n",
        "    raise HTTPException(status_code=404, detail=\"Pedido não encontrado\")\n",
        "\n",
        "print(\"✅ Serviço de Pedidos definido!\")"
      ],
      "id": "223062dc",
      "execution_count": 29,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "🛠️ Definindo Serviço de Pedidos...\n",
            "✅ Serviço de Pedidos definido!\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "bc054aa5",
        "outputId": "ca57899a-97c0-4850-a697-cd0e12d86022"
      },
      "source": [
        "# Aplicativo Principal / Orquestrador\n",
        "# This app will simulate communication between services and provide entry points\n",
        "from fastapi import FastAPI, HTTPException\n",
        "from fastapi.middleware.cors import CORSMiddleware\n",
        "\n",
        "print(\"🛠️ Definindo Aplicativo Principal / Orquestrador...\")\n",
        "\n",
        "# The main app needs CORS middleware to handle requests from a browser\n",
        "app_main = FastAPI(title=\"Sistema de Microsserviços Orquestrador\")\n",
        "\n",
        "# Configure CORS for the main app\n",
        "app_main.add_middleware(\n",
        "    CORSMiddleware,\n",
        "    allow_origins=[\"*\"],\n",
        "    allow_credentials=True,\n",
        "    allow_methods=[\"*\"],\n",
        "    allow_headers=[\"*\"],\n",
        ")\n",
        "\n",
        "\n",
        "# ================== ROTAS DO APLICATIVO PRINCIPAL ==================\n",
        "@app_main.get(\"/\")\n",
        "def home():\n",
        "    return {\n",
        "        \"sistema\": \"Microsserviços Educacionais\",\n",
        "        \"status\": \"Online 🚀\",\n",
        "        \"servicos_simulados\": {\n",
        "            \"usuarios\": \"interno (simulado)\",\n",
        "            \"produtos\": \"interno (simulado)\",\n",
        "            \"pedidos\": \"interno (simulado)\",\n",
        "            \"demonstracao_comunicacao\": \"/pedido-completo/1\"\n",
        "        },\n",
        "        \"explicacao\": \"Este é o orquestrador, simulando comunicação interna.\"\n",
        "    }\n",
        "\n",
        "@app_main.get(\"/health\")\n",
        "def health_check():\n",
        "    \"\"\"Verificar status de todos os serviços simulados\"\"\"\n",
        "    # In a real scenario, this would check the health of each actual service\n",
        "    return {\n",
        "        \"status\": \"healthy\",\n",
        "        \"servicos_simulados\": {\n",
        "            \"usuarios\": \"simulado_online\",\n",
        "            \"produtos\": \"simulado_online\",\n",
        "            \"pedidos\": \"simulado_online\"\n",
        "        }\n",
        "    }\n",
        "\n",
        "# ================== DEMONSTRAÇÃO: COMUNICAÇÃO ENTRE SERVIÇOS ==================\n",
        "@app_main.get(\"/pedido-completo/{pedido_id}\")\n",
        "def pedido_completo(pedido_id: int):\n",
        "    \"\"\"\n",
        "    🎯 DEMONSTRAÇÃO DE COMUNICAÇÃO ENTRE MICROSSERVIÇOS (Simulada)\n",
        "\n",
        "    Esta rota simula como microsserviços se comunicariam:\n",
        "    - Busca informações do pedido (simulando chamada ao serviço de pedidos)\n",
        "    - Busca informações do usuário (simulando chamada ao serviço de usuários)\n",
        "    - Busca informações do produto (simulando chamada ao serviço de produtos)\n",
        "    - Combina tudo em uma resposta mais detalhada\n",
        "    \"\"\"\n",
        "\n",
        "    #Como se trata de uma simulação dentro de um processo, acessamos diretamente os dados/funções\n",
        "# Em uma arquitetura de microsserviço real, isso seria feito por meio de solicitações HTTP (por exemplo, usando a biblioteca `requests`)\n",
        "\n",
        "    # 1. Buscar pedido (simulando chamada ao serviço de pedidos)\n",
        "    # Access the data directly from the pedidos_db defined in the pedidos service cell\n",
        "    pedido = None\n",
        "    # Assume pedidos_db is accessible (due to notebook environment, normally not the case)\n",
        "    global pedidos_db # Access the global variable defined in the pedidos cell\n",
        "    for p in pedidos_db:\n",
        "        if p[\"id\"] == pedido_id:\n",
        "            pedido = p\n",
        "            break\n",
        "\n",
        "    if not pedido:\n",
        "        raise HTTPException(status_code=404, detail=\"Pedido não encontrado na simulação\")\n",
        "\n",
        "    # 2. Buscar usuário (simulando chamada ao serviço de usuários)\n",
        "    # Access the data directly from the usuarios_db defined in the usuarios service cell\n",
        "    usuario = None\n",
        "    global usuarios_db # Access the global variable defined in the usuarios cell\n",
        "    for u in usuarios_db:\n",
        "        if u[\"id\"] == pedido[\"usuario_id\"]:\n",
        "            usuario = u\n",
        "            break\n",
        "\n",
        "    # 3. Buscar produto (simulando chamada ao serviço de produtos)\n",
        "    # Access the data directly from the produtos_db defined in the produtos service cell\n",
        "    produto = None\n",
        "    global produtos_db # Access the global variable defined in the produtos cell\n",
        "    for p in produtos_db:\n",
        "        if p[\"id\"] == pedido[\"produto_id\"]:\n",
        "            produto = p\n",
        "            break\n",
        "\n",
        "    # 4. Montar resposta completa e mais detalhada\n",
        "    response_data = {\n",
        "        \"demonstracao\": \"Comunicação entre Microsserviços (Simulada)\",\n",
        "        \"pedido_id\": pedido_id,\n",
        "        \"detalhes_pedido\": {\n",
        "            \"quantidade\": pedido[\"quantidade\"],\n",
        "            \"status\": pedido[\"status\"]\n",
        "        },\n",
        "        \"dados_usuario\": usuario if usuario else {\"erro\": \"Usuário não encontrado na simulação\"},\n",
        "        \"dados_produto\": produto if produto else {\"erro\": \"Produto não encontrado na simulação\"},\n",
        "        \"explicacao\": \"Este endpoint simula como 3 microsserviços diferentes se comunicariam internamente.\"\n",
        "    }\n",
        "\n",
        "    # Adicionar valor total se o produto for encontrado\n",
        "    if produto:\n",
        "        response_data[\"valor_total\"] = produto[\"preco\"] * pedido[\"quantidade\"]\n",
        "    else:\n",
        "        response_data[\"valor_total\"] = 0\n",
        "\n",
        "\n",
        "    return response_data\n",
        "\n",
        "print(\"✅ Aplicativo Principal / Orquestrador definido!\")"
      ],
      "id": "bc054aa5",
      "execution_count": 30,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "🛠️ Definindo Aplicativo Principal / Orquestrador...\n",
            "✅ Aplicativo Principal / Orquestrador definido!\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Pessoal vamos entender primeiro e depois vamos entender o código, aqui uma parada na sinaleira pra seguir com o código**"
      ],
      "metadata": {
        "id": "7DKr83OFOdU3"
      },
      "id": "7DKr83OFOdU3"
    },
    {
      "cell_type": "markdown",
      "source": [
        "Explicação Detalhada da Simulação de Microsserviços no Colab\n",
        "Olá! Agora que estruturamos nosso código e simulamos a execução em portas separadas, vamos entender o que realmente fizemos aqui no ambiente do Google Colab e como isso se relaciona com uma arquitetura de microsserviços real.\n",
        "\n",
        "1. O Conceito de Microsserviços\n",
        "Como vimos, microsserviços são pequenas aplicações independentes. Pense neles como blocos de construção, onde cada bloco faz uma coisa específica (gerenciar usuários, processar pedidos, listar produtos). Em um sistema real:\n",
        "\n",
        "Cada microsserviço roda em seu próprio processo ou servidor.\n",
        "Eles se comunicam exclusivamente através da rede, geralmente usando protocolos como HTTP/REST (como se fosse a internet interna da sua aplicação) ou gRPC.\n",
        "São independentes para serem desenvolvidos, implantados e escalados (aumentar a capacidade) individualmente.\n",
        "2. Como Nossa Simulação no Colab Funciona\n",
        "Nossa estrutura no notebook (com app_usuarios, app_pedidos, app_main) simula essa separação arquitetônica conceitualmente:\n",
        "\n",
        "Criamos instâncias FastAPI separadas para cada \"serviço\", definindo suas rotas e lógica de forma modular. Isso imita a organização de código que você teria se cada serviço estivesse em arquivos ou projetos distintos.\n",
        "O app_main atua como um orquestrador ou uma simulação de API Gateway, sendo o ponto de entrada para algumas requisições e orquestrando chamadas entre os \"serviços\" internos.\n",
        "3. Limitações da Execução Simultânea no Colab\n",
        "Você deve ter percebido que não conseguimos rodar os três serviços (app_usuarios, app_pedidos, app_produtos) e o app_main ao mesmo tempo em portas diferentes usando uvicorn.run() em uma única célula. Por quê?\n",
        "\n",
        "uvicorn.run() é uma função bloqueante. Quando você a chama, ela assume o controle da execução Python naquela célula e inicia o servidor, esperando por requisições. Ela não retorna até que o servidor seja parado.\n",
        "O ambiente de execução do Google Colab geralmente é um único processo Python. Você não pode simplesmente iniciar vários servidores web independentes e simultâneos chamando uvicorn.run() várias vezes na mesma execução de código.\n",
        "Portanto, embora tenhamos configurado cada FastAPI para uma porta diferente, a execução sequencial significa que apenas o primeiro uvicorn.run() (se não houver erros de porta) seria iniciado de fato.\n",
        "\n",
        "4. Simulação de Comunicação HTTP com requests\n",
        "No nosso endpoint /pedido-completo/{pedido_id}, adaptamos o código para usar a biblioteca requests.\n",
        "\n",
        "Em um ambiente real: O app_main faria requisições HTTP reais para os URLs onde os Serviços de Usuários, Pedidos e Produtos estivessem rodando (ex: http://servico-usuarios:8001/usuarios/123).\n",
        "Na nossa simulação: requests.get(f\"http://localhost:<porta>/...\") simula essas chamadas HTTP. Mesmo que todos os \"serviços\" estejam definidos no mesmo notebook e não rodando simultaneamente em portas ativas no sentido tradicional do Colab, o uso de requests demonstra a forma como a comunicação aconteceria. Ele mostra que um serviço (o Orquestrador) pede informações a outro serviço (Usuários, Pedidos, Produtos) usando um endereço de rede simulado (localhost:<porta>).\n",
        "5. O Que Acontece em uma Implantação Real?\n",
        "Em produção, a história é diferente:\n",
        "\n",
        "Cada um dos seus serviços (app_usuarios, app_pedidos, etc.) seria empacotado e implantado independentemente. Isso é frequentemente feito usando contêineres (como Docker) e orquestradores (como Kubernetes).\n",
        "Cada contêiner rodaria o seu serviço em sua própria porta interna.\n",
        "Um API Gateway ou Load Balancer ficaria na frente, recebendo as requisições externas e as encaminhando para o serviço apropriado. Ele também poderia lidar com autenticação, rate limiting, etc.\n",
        "A comunicação entre os serviços internos ainda seria via rede (HTTP, gRPC).\n",
        "6. Resumo das Limitações e Aprendizado\n",
        "Nossa abordagem no Colab é uma simulação simplificada para fins de aprendizado:\n",
        "\n",
        "Execução Sequencial: Não rodamos serviços simultaneamente em portas vivas no sentido tradicional.\n",
        "Acesso a Variáveis Globais: Para a demonstração /pedido-completo na versão anterior, acessamos diretamente os dados simulados (global variables). A nova versão com requests é melhor, mas ainda é uma simulação dentro do mesmo ambiente. Em um sistema real, não haveria acesso direto a dados de outros serviços.\n",
        "Sem Escalabilidade Real: Não podemos escalar (aumentar o número de instâncias) de um serviço individualmente.\n",
        "Apesar dessas limitações, a simulação nos ajuda a:\n",
        "\n",
        "Entender a estrutura modular do código de microsserviços.\n",
        "Visualizar como a comunicação via rede é o padrão.\n",
        "Compreender o papel de um orquestrador ou API Gateway.\n",
        "Próximos Passos para Explorar\n",
        "Se você quiser ir além desta simulação, pode tentar:\n",
        "\n",
        "Rodar os serviços localmente em seu computador, abrindo múltiplos terminais e executando cada serviço separadamente com uvicorn <nome_arquivo>:<instancia_fastapi> --port <porta>.\n",
        "Explorar Docker para empacotar cada serviço em um contêiner e usar docker-compose para orquestrá-los e permitir que se comuniquem.\n",
        "Esperamos que esta explicação tenha clareado como nossa simulação se encaixa no mundo real dos microsserviços!"
      ],
      "metadata": {
        "id": "ASAxHh6ROAI0"
      },
      "id": "ASAxHh6ROAI0"
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "language_info": {
      "name": "python"
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}