feat: add global task framework (#36368)

This commit is contained in:
Ville Brofeldt
2026-02-09 10:45:56 -08:00
committed by GitHub
parent 6984e93171
commit 59dd2fa385
89 changed files with 15535 additions and 291 deletions

View File

@@ -14,7 +14,9 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from typing import Any, Dict, List, Optional, Tuple
from __future__ import annotations
from typing import Any
import redis
from flask_caching.backends.rediscache import RedisCache, RedisSentinelCache
@@ -28,15 +30,15 @@ class RedisCacheBackend(RedisCache):
self,
host: str,
port: int,
password: Optional[str] = None,
password: str | None = None,
db: int = 0,
default_timeout: int = 300,
key_prefix: Optional[str] = None,
key_prefix: str | None = None,
ssl: bool = False,
ssl_certfile: Optional[str] = None,
ssl_keyfile: Optional[str] = None,
ssl_certfile: str | None = None,
ssl_keyfile: str | None = None,
ssl_cert_reqs: str = "required",
ssl_ca_certs: Optional[str] = None,
ssl_ca_certs: str | None = None,
**kwargs: Any,
) -> None:
super().__init__(
@@ -61,12 +63,61 @@ class RedisCacheBackend(RedisCache):
**kwargs,
)
def set(
self,
name: str,
value: Any,
ex: int | None = None,
px: int | None = None,
nx: bool = False,
xx: bool = False,
) -> bool | None:
"""
Set the value at key ``name``.
:param name: Key name
:param value: Value to set
:param ex: Expire time in seconds
:param px: Expire time in milliseconds
:param nx: If True, set only if key does not exist
:param xx: If True, set only if key already exists
:returns: True if set successfully, None if nx/xx condition not met
"""
return self._cache.set(name, value, ex=ex, px=px, nx=nx, xx=xx)
def delete(self, *names: str) -> int:
"""
Delete one or more keys.
:param names: Key names to delete
:returns: Number of keys deleted
"""
return self._cache.delete(*names)
def publish(self, channel: str, message: str) -> int:
"""
Publish a message to a Redis pub/sub channel.
:param channel: The channel name to publish to
:param message: The message to publish
:returns: Number of subscribers that received the message
"""
return self._cache.publish(channel, message)
def pubsub(self) -> redis.client.PubSub:
"""
Create a pub/sub subscription object.
:returns: PubSub object for subscribing to channels
"""
return self._cache.pubsub()
def xadd(
self,
stream_name: str,
event_data: Dict[str, Any],
event_data: dict[str, Any],
event_id: str = "*",
maxlen: Optional[int] = None,
maxlen: int | None = None,
) -> str:
return self._cache.xadd(stream_name, event_data, event_id, maxlen)
@@ -75,13 +126,13 @@ class RedisCacheBackend(RedisCache):
stream_name: str,
start: str = "-",
end: str = "+",
count: Optional[int] = None,
) -> List[Any]:
count: int | None = None,
) -> list[Any]:
count = count or self.MAX_EVENT_COUNT
return self._cache.xrange(stream_name, start, end, count)
@classmethod
def from_config(cls, config: Dict[str, Any]) -> "RedisCacheBackend":
def from_config(cls, config: dict[str, Any]) -> RedisCacheBackend:
kwargs = {
"host": config.get("CACHE_REDIS_HOST", "localhost"),
"port": config.get("CACHE_REDIS_PORT", 6379),
@@ -108,18 +159,18 @@ class RedisSentinelCacheBackend(RedisSentinelCache):
def __init__( # pylint: disable=too-many-arguments
self,
sentinels: List[Tuple[str, int]],
sentinels: list[tuple[str, int]],
master: str,
password: Optional[str] = None,
sentinel_password: Optional[str] = None,
password: str | None = None,
sentinel_password: str | None = None,
db: int = 0,
default_timeout: int = 300,
key_prefix: str = "",
ssl: bool = False,
ssl_certfile: Optional[str] = None,
ssl_keyfile: Optional[str] = None,
ssl_certfile: str | None = None,
ssl_keyfile: str | None = None,
ssl_cert_reqs: str = "required",
ssl_ca_certs: Optional[str] = None,
ssl_ca_certs: str | None = None,
**kwargs: Any,
) -> None:
# Sentinel dont directly support SSL
@@ -177,12 +228,61 @@ class RedisSentinelCacheBackend(RedisSentinelCache):
**kwargs,
)
def set(
self,
name: str,
value: Any,
ex: int | None = None,
px: int | None = None,
nx: bool = False,
xx: bool = False,
) -> bool | None:
"""
Set the value at key ``name``.
:param name: Key name
:param value: Value to set
:param ex: Expire time in seconds
:param px: Expire time in milliseconds
:param nx: If True, set only if key does not exist
:param xx: If True, set only if key already exists
:returns: True if set successfully, None if nx/xx condition not met
"""
return self._cache.set(name, value, ex=ex, px=px, nx=nx, xx=xx)
def delete(self, *names: str) -> int:
"""
Delete one or more keys.
:param names: Key names to delete
:returns: Number of keys deleted
"""
return self._cache.delete(*names)
def publish(self, channel: str, message: str) -> int:
"""
Publish a message to a Redis pub/sub channel.
:param channel: The channel name to publish to
:param message: The message to publish
:returns: Number of subscribers that received the message
"""
return self._cache.publish(channel, message)
def pubsub(self) -> redis.client.PubSub:
"""
Create a pub/sub subscription object.
:returns: PubSub object for subscribing to channels
"""
return self._cache.pubsub()
def xadd(
self,
stream_name: str,
event_data: Dict[str, Any],
event_data: dict[str, Any],
event_id: str = "*",
maxlen: Optional[int] = None,
maxlen: int | None = None,
) -> str:
return self._cache.xadd(stream_name, event_data, event_id, maxlen)
@@ -191,13 +291,13 @@ class RedisSentinelCacheBackend(RedisSentinelCache):
stream_name: str,
start: str = "-",
end: str = "+",
count: Optional[int] = None,
) -> List[Any]:
count: int | None = None,
) -> list[Any]:
count = count or self.MAX_EVENT_COUNT
return self._cache.xrange(stream_name, start, end, count)
@classmethod
def from_config(cls, config: Dict[str, Any]) -> "RedisSentinelCacheBackend":
def from_config(cls, config: dict[str, Any]) -> RedisSentinelCacheBackend:
kwargs = {
"sentinels": config.get("CACHE_REDIS_SENTINELS", [("127.0.0.1", 26379)]),
"master": config.get("CACHE_REDIS_SENTINEL_MASTER", "mymaster"),