diff --git a/.github/workflows/fusion-docs.yml b/.github/workflows/fusion-docs.yml index c82840512..75a74ffa6 100644 --- a/.github/workflows/fusion-docs.yml +++ b/.github/workflows/fusion-docs.yml @@ -1,7 +1,6 @@ on: - push: - tags: - - 'v*.*.*' + release: + types: [published] name: Generate Fusion docs @@ -36,6 +35,6 @@ jobs: - name: Upload release asset run: | - gh release upload ${{ github.ref_name }} fusion-docs.zip + gh release upload ${{ github.event.release.tag_name }} fusion-docs.zip env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index fe684d0c7..1a0e6d0a6 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -7,6 +7,12 @@ name: Publish packages on: + push: + tags: + - 'v*-rc*' + - 'v*-test*' + - 'v*-alpha*' + - 'v*-beta*' release: types: [published] workflow_dispatch: @@ -157,15 +163,17 @@ jobs: runs-on: ubuntu-latest permissions: - id-token: write # Required for OIDC trusted publishing - actions: read # Required for actions/download-artifact - contents: read # Required for repository access + id-token: write # Required for OIDC trusted publishing + actions: read # Required for actions/download-artifact + contents: write # Required for gh release create/upload environment: name: publish url: https://pypi.org/p/singlestoredb steps: + - uses: actions/checkout@v3 + - name: Download Linux wheels and sdist uses: actions/download-artifact@v4 with: @@ -184,8 +192,26 @@ jobs: name: artifacts-macOS path: dist + - name: Create GitHub Release (test tag) + if: github.event_name == 'push' + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create "${{ github.ref_name }}" \ + --prerelease \ + --title "${{ github.ref_name }}" \ + --notes "" \ + dist/* + + - name: Upload assets to existing Release + if: github.event_name == 'release' + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release upload "${{ github.event.release.tag_name }}" dist/* --clobber + - name: Publish to PyPI - if: ${{ github.event_name == 'release' || github.event.inputs.publish_pypi == 'true' }} + if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.publish_pypi == 'true') }} uses: pypa/gh-action-pypi-publish@release/v1 # - name: Publish Conda package diff --git a/singlestoredb/functions/ext/asgi.py b/singlestoredb/functions/ext/asgi.py index d9090b38f..f70b1ec16 100755 --- a/singlestoredb/functions/ext/asgi.py +++ b/singlestoredb/functions/ext/asgi.py @@ -113,6 +113,28 @@ async def to_thread( return await loop.run_in_executor(None, func_call) +async def _poll_cancel(cancel_event: threading.Event) -> None: + while not cancel_event.is_set(): + await asyncio.sleep(0.1) + + +async def _cancellable_run( + cancel_event: threading.Event, + coro: Any, +) -> Any: + task = asyncio.create_task(coro) + cancel_check = asyncio.create_task(_poll_cancel(cancel_event)) + done, pending = await asyncio.wait( + [task, cancel_check], return_when=asyncio.FIRST_COMPLETED, + ) + for p in pending: + p.cancel() + if cancel_check in done: + task.cancel() + raise asyncio.CancelledError() + return task.result() + + # Use negative values to indicate unsigned ints / binary data / usec time precision rowdat_1_type_map = { 'bool': ft.LONGLONG, @@ -1190,11 +1212,12 @@ async def __call__( ) func_task = asyncio.create_task( - func(cancel_event, call_timer, *inputs) - if func_info['is_async'] - else to_thread( + to_thread( lambda: asyncio.run( - func(cancel_event, call_timer, *inputs), + _cancellable_run( + cancel_event, + func(cancel_event, call_timer, *inputs), + ), ), ), ) @@ -1214,6 +1237,8 @@ async def __call__( ) await cancel_all_tasks(pending) + if func_task in pending: + cancel_event.set() for task in done: if task is disconnect_task: @@ -1286,6 +1311,7 @@ async def __call__( await send(self.error_response_dict) finally: + cancel_event.set() await cancel_all_tasks(all_tasks) # Handle api reflection diff --git a/singlestoredb/tests/test_connection.py b/singlestoredb/tests/test_connection.py index ee392d06a..2ae5cf1d2 100755 --- a/singlestoredb/tests/test_connection.py +++ b/singlestoredb/tests/test_connection.py @@ -22,8 +22,10 @@ try: import pandas as pd has_pandas = True + _pd_str_dtype = str(pd.DataFrame({'a': ['x']}).dtypes['a']) except ImportError: has_pandas = False + _pd_str_dtype = 'object' class TestConnection(unittest.TestCase): @@ -1124,21 +1126,21 @@ def test_alltypes_pandas(self): ('timestamp', 'datetime64[us]'), ('timestamp_6', 'datetime64[us]'), ('year', 'float64'), - ('char_100', 'object'), + ('char_100', _pd_str_dtype), ('binary_100', 'object'), - ('varchar_200', 'object'), + ('varchar_200', _pd_str_dtype), ('varbinary_200', 'object'), - ('longtext', 'object'), - ('mediumtext', 'object'), - ('text', 'object'), - ('tinytext', 'object'), + ('longtext', _pd_str_dtype), + ('mediumtext', _pd_str_dtype), + ('text', _pd_str_dtype), + ('tinytext', _pd_str_dtype), ('longblob', 'object'), ('mediumblob', 'object'), ('blob', 'object'), ('tinyblob', 'object'), ('json', 'object'), - ('enum', 'object'), - ('set', 'object'), + ('enum', _pd_str_dtype), + ('set', _pd_str_dtype), ('bit', 'object'), ] @@ -1266,21 +1268,21 @@ def test_alltypes_no_nulls_pandas(self): ('timestamp', 'datetime64[us]'), ('timestamp_6', 'datetime64[us]'), ('year', 'int16'), - ('char_100', 'object'), + ('char_100', _pd_str_dtype), ('binary_100', 'object'), - ('varchar_200', 'object'), + ('varchar_200', _pd_str_dtype), ('varbinary_200', 'object'), - ('longtext', 'object'), - ('mediumtext', 'object'), - ('text', 'object'), - ('tinytext', 'object'), + ('longtext', _pd_str_dtype), + ('mediumtext', _pd_str_dtype), + ('text', _pd_str_dtype), + ('tinytext', _pd_str_dtype), ('longblob', 'object'), ('mediumblob', 'object'), ('blob', 'object'), ('tinyblob', 'object'), ('json', 'object'), - ('enum', 'object'), - ('set', 'object'), + ('enum', _pd_str_dtype), + ('set', _pd_str_dtype), ('bit', 'object'), ]