Skip to content

Add AsyncClient wrapper and docs#419

Merged
N4S4 merged 3 commits into
masterfrom
feature/async-client
Jun 30, 2026
Merged

Add AsyncClient wrapper and docs#419
N4S4 merged 3 commits into
masterfrom
feature/async-client

Conversation

@N4S4

@N4S4 N4S4 commented Jun 9, 2026

Copy link
Copy Markdown
Owner

🗃️ Summary

Add an async client wrapper (AsyncClient) that makes all existing synology-api classes awaitable without duplicating any business logic — a single 80-line module.


🚀 Motivation & Problem Statement

synology-api currently uses synchronous requests for all HTTP calls. Users building async applications (FastAPI, Telegram bots, Home Assistant integrations, etc.) cannot make non-blocking calls or run parallel API requests.

Duplicating all API modules with aiohttp would create a maintenance nightmare — every new method would need to be written twice.

This PR introduces a zero-duplication approach: a thread-pool wrapper that makes every existing sync method awaitable automatically.


🔧 Implementation Details

New files:

  • synology_api/async_client.pyAsyncClient class. Wraps any sync class instance and intercepts all public method calls via __getattr__, dispatching them to loop.run_in_executor().

Modified files:

  • synology_api/__init__.py — Added async_client to module imports.
  • README.md — Added "Async Client (beta)" section with usage examples.
  • documentation/docs/getting-started/async.md — Full async documentation page with quick-start, concurrent calls, and cleanup examples.

No dependencies added — uses only asyncio from the standard library.

Tested against real NAS not all modules:

  • 12 modules pass (AudioStation, CorePackage, CoreServiceHW, CoreSysInfo, DHCPServer, DownloadStation, DriveAdminConsole, FileStation, NoteStation, Photos, SecurityAdvisor, VPN)
  • Concurrent calls in asyncio.gather achieve ~3x speedup vs serial

🏁 Checklist

  • I have read and followed the Contributing guidelines.
  • All new or modified code is covered by unit tests (tests/).
  • Tests pass locally (pytest).
  • I added or updated documentation where necessary.
  • I updated the changelog or added a new section if this is a major change.
  • I followed the style guidelines (black, flake8, etc.).
  • I ran pre-commit and addressed any linting issues.

Note: If you added a new API wrapper, please update docs/ and add the
corresponding entries to APIs - Supported APIs in the README.


📝 Related Issue

new feature


🔨 Additional Notes

Known limitations:

  • Uses thread-pool executor (run_in_executor), not native aiohttp. Adds ~1ms overhead per call. For applications making thousands of parallel requests, a future native async transport can be added without changing the API.
  • Session reuse: each AsyncClient instance wraps one sync instance. For optimal performance, reuse the wrapped instance or enable shared sessions.

Performance:

  • 3 parallel get_file_list calls: 0.43s vs ~1.29s serial → ~3x speedup.
  • No measurable overhead for single calls vs raw sync.

Future work:

  • Add native aiohttp transport as an opt-in backend (same AsyncClient interface, just swap the executor).
  • Add progress callbacks for async uploads/downloads.

😎 Test & Build Status

Tested against real Synology NAS (DSM 7.3.2):

AsyncClient — module test 
  ✅ audiostation                   [3.55s]  ok
  ✅ core_package                   [0.32s]  ok
  ✅ core_service_hw                [1.00s]  ok
  ✅ core_sys_info                  [0.27s]  ok
  ✅ dhcp_server                    [0.33s]  ok
  ✅ downloadstation                [1.03s]  ok
  ✅ drive_admin_console            [4.93s]  ok
  ✅ filestation                    [2.36s]  ok
  ✅ notestation                    [1.10s]  ok
  ✅ photos                         [2.89s]  ok
  ✅ security_advisor               [6.33s]  ok
  ✅ vpn                            [0.47s]  ok
Total: 12 passed, 0 failed

👀 Screenshots / Media

none


Thank you for contributing! 🙏

Introduce AsyncClient: a lightweight wrapper that makes existing synchronous synology-api classes awaitable by dispatching calls to the event loop's thread-pool (using loop.run_in_executor). Export async_client from the package, add README snippet and a new detailed getting-started async documentation page showing usage, concurrent calls, and async context-manager cleanup (auto-logout). No new dependencies required; aimed at enabling easy async usage of existing APIs.
@N4S4 N4S4 requested a review from joeperpetua June 9, 2026 21:46
N4S4 added 2 commits June 9, 2026 17:52
Mark AsyncClient as finished in docs_status.yaml and expand inline documentation in synology_api/async_client.py. Added detailed docstrings for _make_async_callable, the AsyncClient class, and its __getattr__, __aenter__, and __aexit__ methods (parameters, returns, and behavior). No functional logic changes—these edits improve readability and debugging/tracing context.
Refactor and expand inline documentation in synology_api/async_client.py. Adds a full docstring to the async wrapper returned by _make_async_callable (including parameters and return), documents AsyncClient.__init__ (describing the sync instance), tightens class/docstring wording, clarifies __getattr__ summary, and expands __aenter__/__aexit__ docstrings with return/parameter details. These are documentation/formatting changes only and do not alter runtime behavior.
@N4S4

N4S4 commented Jun 9, 2026

Copy link
Copy Markdown
Owner Author

@joeperpetua do you think is a good idea in first place? I know is not pure async but the easiest way to integrate... I think

@joeperpetua

Copy link
Copy Markdown
Collaborator

yeah why not, I will try to take a look today 😁

@joeperpetua

Copy link
Copy Markdown
Collaborator

Looks good!

@N4S4 N4S4 merged commit 1111d66 into master Jun 30, 2026
5 checks passed
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.

2 participants