Skip to content

Replace private psycopg2/Bolt API usage with public interfaces for he…#83

Merged
wpak-ai merged 3 commits into
developfrom
refactor/public-health-api
Jul 2, 2026
Merged

Replace private psycopg2/Bolt API usage with public interfaces for he…#83
wpak-ai merged 3 commits into
developfrom
refactor/public-health-api

Conversation

@henry0816191

@henry0816191 henry0816191 commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Use pool_status() with only public getconn/putconn for DB pool health checks (with pinned minimum version note).
  • Replace app.start() + private app._development_server._server shutdown with an owned HTTPServer that dispatches via public App.dispatch().
  • Inline Bolt server shutdown in shutdown_services() using bolt_server.shutdown(), matching the health server pattern.

Why

Private slack-bolt and psycopg2 internals created undocumented version coupling: minor dependency bumps could break health checks or graceful shutdown without clear test failures.

Test plan

  • pytest tests/test_db.py tests/test_shutdown.py tests/test_bolt_server.py tests/test_main_health_merge.py
  • Full suite passes (413 passed)

Related issue

Summary by CodeRabbit

  • New Features
    • Added a dedicated lightweight HTTP server for handling Slack event HTTP requests and routing them through the app dispatcher.
  • Bug Fixes
    • Improved unsupported-path/method handling with consistent 404 responses and correct response serialization.
    • Refined shutdown so the Slack event HTTP server is stopped and closed cleanly on exit.
  • Tests
    • Added end-to-end tests for Slack event request forwarding, status/body handling, and JSON responses.
    • Updated shutdown/health-check coverage, including database pool health propagation.
  • Documentation
    • Clarified the required version range for the database liveness probe.

@henry0816191 henry0816191 requested a review from wpak-ai as a code owner July 1, 2026 19:29
@henry0816191 henry0816191 self-assigned this Jul 1, 2026
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2008b986-a613-4315-89b0-df84262458d8

📥 Commits

Reviewing files that changed from the base of the PR and between bf0e392 and 8aea235.

📒 Files selected for processing (1)
  • src/paperscout/shutdown.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/paperscout/shutdown.py

📝 Walkthrough

Walkthrough

This PR replaces the Slack Bolt server startup with a stdlib HTTPServer, updates shutdown to stop that server directly, and adds coverage for Bolt dispatch, shutdown behavior, and health merging. It also updates the pool_status docstring.

Changes

Bolt HTTP server and shutdown updates

Layer / File(s) Summary
Bolt HTTP server implementation
src/paperscout/bolt_server.py
Adds create_bolt_http_server with request handling for POST /slack/events, app.dispatch calls, response serialization, and 404 handling for other requests.
Entrypoint wiring
src/paperscout/__main__.py
Creates bolt_server in _async_main, runs bolt_server.serve_forever(...) in a background thread, and passes bolt_server into shutdown handling.
Shutdown flow
src/paperscout/shutdown.py
Removes the Bolt App shutdown helper, changes shutdown_services to accept `bolt_server: HTTPServer
Server and shutdown tests
tests/test_bolt_server.py, tests/test_shutdown.py
Adds live HTTP coverage for Bolt dispatch, invalid methods and paths, JSON response bodies, and updates shutdown tests for the new server parameter.
Health merge and pool doc
src/paperscout/db.py, tests/test_main_health_merge.py
Updates the pool_status docstring and adds a health-merge test that includes db_pool data from pool_status().

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • cppalliance/paperscout#58: Both PRs change Slack startup and shutdown wiring in src/paperscout/__main__.py and src/paperscout/shutdown.py.
  • cppalliance/paperscout#82: Both PRs modify the shared shutdown_services(...) path in src/paperscout/shutdown.py.

Suggested labels: bug

Suggested reviewers: wpak-ai

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR appears to add pool closure, but it doesn't show the required finally block, zero-active-connection test, or shutdown logging for #80. Add pool.closeall() in a finally block, verify zero active connections after shutdown, and log pool closure at shutdown.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: replacing private psycopg2/Bolt usage with public interfaces.
Description check ✅ Passed The PR description includes Summary, Test plan, and issue linkage, so it mostly matches the template despite a different related-issues heading.
Out of Scope Changes check ✅ Passed The changes stay focused on DB health checks, Bolt server ownership, shutdown cleanup, and related tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/public-health-api

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/paperscout/shutdown.py (1)

55-63: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Close both HTTPServer sockets after joining their threads. shutdown() stops serve_forever(), but the listening socket stays open. Add server_close() for both health_server and bolt_server so their ports are released cleanly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/paperscout/shutdown.py` around lines 55 - 63, After calling shutdown and
joining the threads in the shutdown flow, also close the listening sockets so
the ports are released cleanly. Update the shutdown logic around the
health_server and bolt_server handling in shutdown() to call server_close() for
each server after their corresponding _join_thread() completes, keeping the
existing exception logging intact.
🧹 Nitpick comments (1)
tests/test_shutdown.py (1)

90-105: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

This test still doesn't prove the pool is actually drained.

Issue #80 asks for a post-shutdown “zero active connections” check. A plain MagicMock only proves closeall() was called, so this test still passes if checked-out connections remain leaked. Please add an assertion against real pool state (for example via pool_status(pool) or a lightweight fake that tracks active leases).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_shutdown.py` around lines 90 - 105, The shutdown test only
verifies that shutdown_services() calls pool.closeall(), so it does not validate
the required zero-active-connections state. Update
test_shutdown_services_closes_pool to assert the pool is fully drained after
shutdown by checking real pool status via pool_status(pool) or by using a
lightweight fake pool that tracks checked-out leases. Keep the existing
shutdown_services and pool.closeall assertions, but add a post-shutdown
assertion that confirms no active connections remain.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_bolt_server.py`:
- Around line 24-43: Update the bolt_server_url fixture teardown so it fully
releases the HTTP server resources: in the fixture that uses
create_bolt_http_server, call server.server_close() after server.shutdown() to
close the listening socket, and replace the current thread.join(timeout=2)
cleanup with a join followed by an assertion that the serve_forever thread is no
longer alive. Use the existing bolt_server_url fixture, create_bolt_http_server,
and the thread object to locate the change.

---

Outside diff comments:
In `@src/paperscout/shutdown.py`:
- Around line 55-63: After calling shutdown and joining the threads in the
shutdown flow, also close the listening sockets so the ports are released
cleanly. Update the shutdown logic around the health_server and bolt_server
handling in shutdown() to call server_close() for each server after their
corresponding _join_thread() completes, keeping the existing exception logging
intact.

---

Nitpick comments:
In `@tests/test_shutdown.py`:
- Around line 90-105: The shutdown test only verifies that shutdown_services()
calls pool.closeall(), so it does not validate the required
zero-active-connections state. Update test_shutdown_services_closes_pool to
assert the pool is fully drained after shutdown by checking real pool status via
pool_status(pool) or by using a lightweight fake pool that tracks checked-out
leases. Keep the existing shutdown_services and pool.closeall assertions, but
add a post-shutdown assertion that confirms no active connections remain.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 05e6b3a1-bac4-466c-b4cb-9b3f10800990

📥 Commits

Reviewing files that changed from the base of the PR and between 4f843db and ace45aa.

📒 Files selected for processing (7)
  • src/paperscout/__main__.py
  • src/paperscout/bolt_server.py
  • src/paperscout/db.py
  • src/paperscout/shutdown.py
  • tests/test_bolt_server.py
  • tests/test_main_health_merge.py
  • tests/test_shutdown.py

Comment thread tests/test_bolt_server.py Outdated
@henry0816191

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review again

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

@henry0816191 Sure, I'll perform a full review of all the changes in this PR again.

✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/test_shutdown.py (1)

90-105: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

The pool-close test does not verify the leak is fixed.

This only checks that closeall() was invoked on a MagicMock. Issue #80 asks for a shutdown test that proves the pool reaches zero active connections; this test would still pass if checked-out connections were leaked. Please switch this to a stateful fake or integration-style pool test and assert the active count is 0 after shutdown_services().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_shutdown.py` around lines 90 - 105, The shutdown pool test
currently only asserts that shutdown_services() calls closeall() on a MagicMock,
which does not prove connections are actually released. Replace the MagicMock
pool in test_shutdown_services_closes_pool with a stateful fake or
integration-style pool that tracks checked-out connections, then verify after
shutdown_services() completes that the pool’s active connection count is 0. Keep
the existing shutdown_services() and pool.closeall() flow, but strengthen the
assertion to validate real connection cleanup rather than just method
invocation.
🧹 Nitpick comments (1)
tests/test_bolt_server.py (1)

18-21: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Avoid the free-port probe race in this fixture.

_find_free_port() releases the socket before the server binds, so another process or parallel test can grab that port and make this suite flaky. Let the server bind to port 0 and read back the assigned port instead.

♻️ Proposed fix
-import socket
@@
-def _find_free_port() -> int:
-    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
-        s.bind(("127.0.0.1", 0))
-        return s.getsockname()[1]
-
-
 `@pytest.fixture`()
 def bolt_server_url():
@@
-    port = _find_free_port()
-    server = create_bolt_http_server(app, port, bind_host="127.0.0.1")
+    server = create_bolt_http_server(app, 0, bind_host="127.0.0.1")
+    port = server.server_address[1]

Also applies to: 33-45

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_bolt_server.py` around lines 18 - 21, The free-port helper in
_find_free_port is causing a race because the socket is closed before the server
starts, so update the test setup to stop probing for a port and instead let the
Bolt server bind to port 0 directly. Then, in the server startup/fixture code
that uses _find_free_port and the Bolt server launch path, read back the actual
assigned port from the bound socket/server object and use that value for the
client connection.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/paperscout/shutdown.py`:
- Around line 55-59: The Bolt server shutdown path in shutdown and bolt_server
handling only calls shutdown(), which stops the loop but leaves the listening
socket open. Update the shutdown logic around bolt_server to call server_close()
after a successful shutdown() so the port is released during teardown, and keep
the existing exception logging in place for failures.

---

Outside diff comments:
In `@tests/test_shutdown.py`:
- Around line 90-105: The shutdown pool test currently only asserts that
shutdown_services() calls closeall() on a MagicMock, which does not prove
connections are actually released. Replace the MagicMock pool in
test_shutdown_services_closes_pool with a stateful fake or integration-style
pool that tracks checked-out connections, then verify after shutdown_services()
completes that the pool’s active connection count is 0. Keep the existing
shutdown_services() and pool.closeall() flow, but strengthen the assertion to
validate real connection cleanup rather than just method invocation.

---

Nitpick comments:
In `@tests/test_bolt_server.py`:
- Around line 18-21: The free-port helper in _find_free_port is causing a race
because the socket is closed before the server starts, so update the test setup
to stop probing for a port and instead let the Bolt server bind to port 0
directly. Then, in the server startup/fixture code that uses _find_free_port and
the Bolt server launch path, read back the actual assigned port from the bound
socket/server object and use that value for the client connection.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cb63cc85-da3f-48b6-a189-71b6b577369b

📥 Commits

Reviewing files that changed from the base of the PR and between 4f843db and bf0e392.

📒 Files selected for processing (7)
  • src/paperscout/__main__.py
  • src/paperscout/bolt_server.py
  • src/paperscout/db.py
  • src/paperscout/shutdown.py
  • tests/test_bolt_server.py
  • tests/test_main_health_merge.py
  • tests/test_shutdown.py

Comment thread src/paperscout/shutdown.py
@wpak-ai wpak-ai merged commit 363cb4c into develop Jul 2, 2026
10 checks passed
@wpak-ai wpak-ai deleted the refactor/public-health-api branch July 2, 2026 15:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Resource management: add pool.closeall() to shutdown_services

2 participants