refactor: migrate service_api and inner_api to sessionmaker pattern#34379
Conversation
…er pattern Part of langgenius#24245. Replace manual Session(db.engine) + session.commit() with sessionmaker(db.engine).begin() context manager for automatic transaction management. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Pyrefly DiffNo changes detected. |
Update test mocks to match the refactored code that uses sessionmaker(db.engine).begin() instead of Session(db.engine). The mock chain is now: sessionmaker() -> .begin() -> __enter__(). Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Pyrefly DiffNo changes detected. |
Pyrefly Diffbase → PR--- /tmp/pyrefly_base.txt 2026-04-01 06:34:58.249330525 +0000
+++ /tmp/pyrefly_pr.txt 2026-04-01 06:34:47.158389448 +0000
@@ -2077,29 +2077,29 @@
ERROR Could not find name `Import` [unknown-name]
--> tests/unit_tests/controllers/inner_api/app/test_dsl.py:117:71
ERROR Missing argument `tenant_model` in function `controllers.inner_api.plugin.wraps.decorated_view` [missing-argument]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:171:44
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:169:44
ERROR Missing argument `user_model` in function `controllers.inner_api.plugin.wraps.decorated_view` [missing-argument]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:171:44
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:169:44
ERROR Missing argument `tenant_model` in function `controllers.inner_api.plugin.wraps.decorated_view` [missing-argument]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:188:31
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:186:31
ERROR Missing argument `user_model` in function `controllers.inner_api.plugin.wraps.decorated_view` [missing-argument]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:188:31
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:186:31
ERROR Missing argument `tenant_model` in function `controllers.inner_api.plugin.wraps.decorated_view` [missing-argument]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:203:35
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:201:35
ERROR Missing argument `user_model` in function `controllers.inner_api.plugin.wraps.decorated_view` [missing-argument]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:203:35
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:201:35
ERROR Missing argument `tenant_model` in function `controllers.inner_api.plugin.wraps.decorated_view` [missing-argument]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:225:44
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:223:44
ERROR Missing argument `user_model` in function `controllers.inner_api.plugin.wraps.decorated_view` [missing-argument]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:225:44
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:223:44
ERROR Argument `type[PluginTestPayload]` is not assignable to parameter `payload_type` with type `type[BaseModel]` in function `controllers.inner_api.plugin.wraps.plugin_data` [bad-argument-type]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:253:35
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:251:35
ERROR Argument `type[PluginTestPayload]` is not assignable to parameter `payload_type` with type `type[BaseModel]` in function `controllers.inner_api.plugin.wraps.plugin_data` [bad-argument-type]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:268:35
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:266:35
ERROR Argument `type[TestPluginData.test_should_raise_error_on_invalid_payload.InvalidPayload]` is not assignable to parameter `payload_type` with type `type[BaseModel]` in function `controllers.inner_api.plugin.wraps.plugin_data` [bad-argument-type]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:286:35
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:284:35
ERROR Argument `type[PluginTestPayload]` is not assignable to parameter `payload_type` with type `type[BaseModel]` in function `controllers.inner_api.plugin.wraps.plugin_data` [bad-argument-type]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:299:35
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:297:35
ERROR Cannot index into `Iterable[bytes]` [bad-index]
--> tests/unit_tests/controllers/service_api/app/test_audio.py:213:16
ERROR Cannot index into `Response` [bad-index]
|
…() pattern sessionmaker().begin() context manager auto-commits on exit, so explicit session.commit() is no longer called in get_user(). Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Pyrefly Diffbase → PR--- /tmp/pyrefly_base.txt 2026-04-01 11:39:18.964249998 +0000
+++ /tmp/pyrefly_pr.txt 2026-04-01 11:39:07.369316640 +0000
@@ -2077,29 +2077,29 @@
ERROR Could not find name `Import` [unknown-name]
--> tests/unit_tests/controllers/inner_api/app/test_dsl.py:117:71
ERROR Missing argument `tenant_model` in function `controllers.inner_api.plugin.wraps.decorated_view` [missing-argument]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:171:44
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:168:44
ERROR Missing argument `user_model` in function `controllers.inner_api.plugin.wraps.decorated_view` [missing-argument]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:171:44
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:168:44
ERROR Missing argument `tenant_model` in function `controllers.inner_api.plugin.wraps.decorated_view` [missing-argument]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:188:31
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:185:31
ERROR Missing argument `user_model` in function `controllers.inner_api.plugin.wraps.decorated_view` [missing-argument]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:188:31
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:185:31
ERROR Missing argument `tenant_model` in function `controllers.inner_api.plugin.wraps.decorated_view` [missing-argument]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:203:35
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:200:35
ERROR Missing argument `user_model` in function `controllers.inner_api.plugin.wraps.decorated_view` [missing-argument]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:203:35
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:200:35
ERROR Missing argument `tenant_model` in function `controllers.inner_api.plugin.wraps.decorated_view` [missing-argument]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:225:44
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:222:44
ERROR Missing argument `user_model` in function `controllers.inner_api.plugin.wraps.decorated_view` [missing-argument]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:225:44
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:222:44
ERROR Argument `type[PluginTestPayload]` is not assignable to parameter `payload_type` with type `type[BaseModel]` in function `controllers.inner_api.plugin.wraps.plugin_data` [bad-argument-type]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:253:35
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:250:35
ERROR Argument `type[PluginTestPayload]` is not assignable to parameter `payload_type` with type `type[BaseModel]` in function `controllers.inner_api.plugin.wraps.plugin_data` [bad-argument-type]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:268:35
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:265:35
ERROR Argument `type[TestPluginData.test_should_raise_error_on_invalid_payload.InvalidPayload]` is not assignable to parameter `payload_type` with type `type[BaseModel]` in function `controllers.inner_api.plugin.wraps.plugin_data` [bad-argument-type]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:286:35
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:283:35
ERROR Argument `type[PluginTestPayload]` is not assignable to parameter `payload_type` with type `type[BaseModel]` in function `controllers.inner_api.plugin.wraps.plugin_data` [bad-argument-type]
- --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:299:35
+ --> tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py:296:35
ERROR Cannot index into `Iterable[bytes]` [bad-index]
--> tests/unit_tests/controllers/service_api/app/test_audio.py:213:16
ERROR Cannot index into `Response` [bad-index]
|
There was a problem hiding this comment.
Pull request overview
Refactors service_api and inner_api controllers to use SQLAlchemy’s sessionmaker(...).begin() context manager pattern instead of Session(...) plus manual commit management, aligning these controllers with prior migrations in the codebase.
Changes:
- Migrated DB session usage in service_api workflow/conversation endpoints to
sessionmaker(db.engine).begin(). - Updated inner_api plugin user lookup/creation to use
sessionmaker(...).begin(), replacingcommit()+refresh()withflush()+refresh(). - Adjusted unit tests to patch/stub
sessionmaker(...).begin()instead ofSession(...).
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| api/controllers/service_api/app/workflow.py | Replaces Session(db.engine) with sessionmaker(db.engine).begin() for workflow log retrieval. |
| api/controllers/service_api/app/conversation.py | Migrates conversation list endpoint session handling to sessionmaker(db.engine).begin(). |
| api/controllers/inner_api/plugin/wraps.py | Migrates to sessionmaker(...).begin(), uses flush() before refresh(), and sets expire_on_commit=False. |
| api/tests/unit_tests/controllers/service_api/app/test_workflow.py | Updates stubs/mocks/patches to match new sessionmaker(...).begin() usage. |
| api/tests/unit_tests/controllers/service_api/app/test_conversation.py | Updates stubs/mocks to patch sessionmaker instead of Session. |
| api/tests/unit_tests/controllers/inner_api/plugin/test_plugin_wraps.py | Updates patches/assertions for sessionmaker(...).begin() behavior and removes commit() expectation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # get paginate workflow app logs | ||
| workflow_app_service = WorkflowAppService() | ||
| with Session(db.engine) as session: | ||
| with sessionmaker(db.engine).begin() as session: |
There was a problem hiding this comment.
sessionmaker(db.engine).begin() will commit on context exit, and with SQLAlchemy’s default expire_on_commit=True this expires ORM instances. This endpoint returns a structure containing ORM-backed LogView/WorkflowAppLog objects that are marshalled after the method returns (outside the session context), which can trigger DetachedInstanceError when the marshaller accesses expired attributes. Consider using expire_on_commit=False for this sessionmaker (or fully serialize the response data inside the context) to avoid returning expired ORM objects.
| with sessionmaker(db.engine).begin() as session: | |
| with sessionmaker(bind=db.engine, expire_on_commit=False).begin() as session: |
Summary
Part of #24245. Migrate
Session(db.engine)+ manualsession.commit()tosessionmaker(db.engine).begin()context manager in service_api and inner_api controllers.This follows the same pattern established by the previous PRs (#24246, #29628, #33966, #34281-#34284) that already migrated the console controllers.
Changes
Session(db.engine)withsessionmaker(db.engine).begin()in 3 files:api/controllers/service_api/app/workflow.pyapi/controllers/service_api/app/conversation.pyapi/controllers/inner_api/plugin/wraps.pysession.commit()calls (handled automatically by the context manager)session.commit()+session.refresh()withsession.flush()+session.refresh()in wraps.py (flush sends to DB for refresh, commit happens automatically on context exit)expire_on_commit=Falsewhere the session object is used outside the context managerSessionimport from workflow.pyCloses part of #24245