Skip to content

Commit

Permalink
Customize timeout for the call (#5)
Browse files Browse the repository at this point in the history
* customize timeout for the call
  • Loading branch information
o-murphy authored Aug 17, 2024
1 parent 7ca735a commit b6766ff
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 12 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
name: Test

on: [push, pull_request]
on:
pull_request:
branches:
- '*'
workflow_dispatch:


jobs:
analyse:
Expand Down
59 changes: 55 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,18 @@ https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md
* [Register AVL Events](#register-avl-events)
* [On login/logout](#on-loginlogout)
* [AVL Events Handling](#avl-events-handling)
* [Register AVL Events handler](#register-avl-events-handlers)
* [Remove AVL Events handler](#remove-avl-events-handlers)
* [Disposable handlers](#disposable-handlers)
* [Exceptions Handling](#exceptions-handling)
* [Get exception results, batch exceptions](#exceptions-handling-batch)
* [Quick API Help](#quick-api-help)
* [Advanced](#advanced-usage)
* [Limitations](#limitations)
* [Prevent polling auto logout](#prevent-polling-logout)
* [Critical requests execution (Render, Reports, Messages)](#critical-requests-execution)
* [Async session lock](#async-session-lock)
* [Timeout for API call](#timeout-for-api-call)
* [Extending AIO Wialon](#extending-aio-wialon)
* [Debugging](#debugging)

Expand All @@ -43,7 +48,7 @@ pip install py-aiowialon
```

## Start Polling
Open session and start poll AVL events immediately
Open session and start poll AVL events immediately.
[Look the Wialon Events section](#wialon-events) to see how we can handle AVL Events on polling
```python
import asyncio
Expand Down Expand Up @@ -236,6 +241,7 @@ async def on_session_close(session_logout):
After polling start and AVL Items registered for polling we can handle the AVL Events.
Use `@wialon.avl_event_handler()` decorator

#### Register AVL Events handlers
```python
from aiowialon import AvlEvent

Expand All @@ -258,6 +264,23 @@ async def unit_734455_event(event: AvlEvent):
> [!NOTE]
> Register handlers in an order in which filters have to be applied. If some handler catched the event, next handler in order will never do.
#### Remove AVL Events handlers
```python
# use them as you need
wialon.remove_avl_event_handler('handler_name')
wialon.remove_avl_event_handler(handler_func)
```

#### Disposable handlers
Use `@wialon.avl_event_once` to be certain that handler will be removed immediately after single execution
```python
@wialon.avl_event_handler()
@wialon.avl_event_once
async def unit_event(event: AvlEvent):
print("Handler got event:", event)
```


## Exceptions Handling
The avl_event_handler suppress the callback's WialonError exceptions to protect app to be closed on unexpected behaviour
So if u want to handle some specific WialonError, do it in handler's callback scope
Expand Down Expand Up @@ -325,10 +348,12 @@ wialon.start_polling(token=TOKEN, logout_finally=False)
```

### Critical requests execution

#### Async session lock
Some requests to services like `Render`, `Reports`, `Messages` requires blocking other requests to be executed together per single session.
* Use the `@wialon.lock_session` decorator to block async loop till your operation done
* You can apply `@wialon.session_lock` also for handlers
* You can use `@wialon.session_lock` inside the methods when [inheriting Wialon](#extending-aio-wialon)
* Use the `@Wialon.lock_session` decorator to block async loop till your operation done
* You can apply `@Wialon.session_lock` also for handlers
* You can use `@Wialon.session_lock` inside the methods when [inheriting Wialon](#extending-aio-wialon)

```python
import asyncio
Expand Down Expand Up @@ -367,6 +392,32 @@ async def unit_event(event: AvlEvent):
```


#### Timeout for API call
Some API calls requires special timeouts, cause them are processing long.
Default timeout for aiohttp request is 5 seconds.
You can set custom timeout on some call executing.
It mostly usefull with `@Wialon.session_lock`
```python
@wialon.avl_event_handler()
@wialon.session_lock
async def unit_event(event: AvlEvent):
try:
await wialon.wait(wialon.messages_load_last(
itemId=event.data.i,
lastTime=event.tm,
lastCount=10000,
flags=0x0000,
flagsMask=0xFF00,
loadCount=10000
), 10)
except (TimeoutError, WialonError) as err:
print(err)
for i in range(5):
print("Waiting exclusive operation", i, "item:", event.data.i)
await asyncio.sleep(1)
```


### Extending AIO Wialon
Inherit from `Wialon` class to add your custom logic and behaviour
* You can directly use `Wialon.request` to make requests to special endpoints
Expand Down
2 changes: 1 addition & 1 deletion aiowialon/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"Mike Turchunovich",
"Dmytro Yaroshenko",
]
__version__ = "1.3.2"
__version__ = "1.3.3"

from aiowialon.logger import *
from aiowialon.utils import *
Expand Down
24 changes: 24 additions & 0 deletions aiowialon/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import json
import warnings
from contextlib import suppress
from functools import wraps
from typing import Callable, Coroutine, Dict, Optional, Any, Union, Literal, List
from urllib.parse import urljoin

Expand Down Expand Up @@ -167,6 +168,19 @@ def wrapper(callback: AvlEventCallback):

return wrapper

def avl_event_once(self, func: Optional[Callable[..., Coroutine[Any, Any, Any]]] = None
) -> Callable[..., Coroutine[Any, Any, Any]]:
"""Be certain that handler will be removed after single execution"""

@wraps(func)
async def wrapper(*args, **kwargs) -> Any:
try:
return await func(*args, **kwargs)
finally:
self.remove_avl_event_handler(func)

return wrapper

def remove_avl_event_handler(self, callback: Union[str, AvlEventCallback]):
"""
Manually remove AVL event handler
Expand Down Expand Up @@ -402,6 +416,16 @@ async def request(self, action_name: str, url: str, payload: Any) -> Any:
logger.exception(e)
raise

async def wait(self, call: Coroutine[Any, Any, Any], timeout: Optional[float] = None) -> Any:
"""Decorate a Call with specified request timeout"""
prev_timeout = self.timeout
if timeout:
self.timeout = timeout
try:
return await call
finally:
self.timeout = prev_timeout

@staticmethod
def help(service_name: str, action_name: str) -> None:
"""
Expand Down
3 changes: 3 additions & 0 deletions aiowialon/api.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Wialon:
def on_session_open(self, callback: LoginCallback | None = None) -> LoginCallback | None: ...
def on_session_close(self, callback: LogoutCallback | None = None) -> LogoutCallback | None: ...
def avl_event_handler(self, filter_: AvlEventFilter | None = None) -> Callable: ...
def avl_event_once(self, func: Callable[..., Coroutine[Any, Any, Any]] | None = None) -> Callable[..., Coroutine[Any, Any, Any]]: ...
def remove_avl_event_handler(self, callback: str | AvlEventCallback): ...
async def start_polling(self, timeout: int | float = 2, logout_finally: bool = True, **params: Unpack[LoginParams]) -> None: ...
async def stop_polling(self, logout: bool = False) -> None: ...
Expand Down Expand Up @@ -371,4 +372,6 @@ class Wialon:
References to requests method
https://sdk.wialon.com/wiki/en/sidebar/remoteapi/apiref/requests/requests
"""

async def apps_list(self, *args: Any, **params: Any) -> Any: ...
# TODO:
21 changes: 15 additions & 6 deletions examples/aiolock.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import asyncio
import logging
from datetime import datetime

from aiowialon import Wialon, flags, AvlEvent
from aiowialon import Wialon, flags, AvlEvent, WialonError

logging.basicConfig(level=logging.INFO)

Expand All @@ -14,6 +15,7 @@ async def locked_task():
for i in range(5):
print("Waiting lock release", i)
await asyncio.sleep(1)

return await locked_task()


Expand All @@ -37,15 +39,22 @@ async def register_avl_events(session_login):


@wialon.avl_event_handler()
@wialon.session_lock # exclusive session lock for callback's frame
@wialon.session_lock
async def unit_event(event: AvlEvent):
await wialon.core_search_item(id=event.data.i, flags=1)
print("Handler got event:", event)
try:
await wialon.wait(wialon.messages_load_last(
itemId=event.data.i,
lastTime=event.tm,
lastCount=10000,
flags=0x0000,
flagsMask=0xFF00,
loadCount=10000
), 10)
except (TimeoutError, WialonError) as err:
print(err)
for i in range(5):
print("Waiting exclusive operation", i, "item:", event.data.i)
await asyncio.sleep(1)
# remove handler
# wialon.remove_avl_event_handler(unit_event)


if __name__ == "__main__":
Expand Down
29 changes: 29 additions & 0 deletions test/aiowait.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import asyncio


class A:

def __init__(self):
self.timeout = 2

async def wait(self, call, timeout):
prev_timeout = self.timeout
if timeout:
self.timeout = timeout
try:
return await call
finally:
self.timeout = prev_timeout

a = A()

async def c():
print(a.timeout)
await asyncio.sleep(3)

async def f():
print(a.timeout)
await a.wait(c(), 10)
print(a.timeout)

asyncio.run(f())

0 comments on commit b6766ff

Please sign in to comment.