Skip to content

Commit ad45c25

Browse files
committed
Rework refresh policy
And allow to force refresh of only the failures list.
1 parent 0b82617 commit ad45c25

File tree

4 files changed

+74
-45
lines changed

4 files changed

+74
-45
lines changed

swattool/main.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from . import swatbuild
1919
from . import userdata
2020
from . import utils
21-
from .webrequests import RefreshPolicy, Session
21+
from .webrequests import Session
2222

2323
logger = logging.getLogger(__name__)
2424

@@ -85,7 +85,7 @@ def login(user: str, password: str):
8585
case_sensitive=False),
8686
help="Specify sort order"),
8787
click.option('--refresh', '-r',
88-
type=click.Choice([p.name for p in RefreshPolicy],
88+
type=click.Choice([p.name for p in swatbotrest.RefreshPolicy],
8989
case_sensitive=False),
9090
default="auto",
9191
help="Fetch data from server instead of using cache"),
@@ -153,7 +153,7 @@ def show_pending_failures(refresh: str, open_url: str,
153153
limit: int, sort: list[str],
154154
**kwargs):
155155
"""Show all failures waiting for triage."""
156-
Session().set_refresh_policy(RefreshPolicy[refresh.upper()])
156+
swatbotrest.RefreshManager().set_policy_by_name(refresh)
157157

158158
filters = parse_filters(kwargs)
159159
builds, userinfos = swatbot.get_failure_infos(limit=limit, sort=sort,
@@ -209,7 +209,7 @@ def review_pending_failures(refresh: str, open_autobuilder_url: bool,
209209
"""Review failures waiting for triage."""
210210
# pylint: disable=too-many-arguments,too-many-positional-arguments
211211

212-
Session().set_refresh_policy(RefreshPolicy[refresh.upper()])
212+
swatbotrest.RefreshManager().set_policy_by_name(refresh)
213213

214214
filters = parse_filters(kwargs)
215215
builds, userinfos = swatbot.get_failure_infos(limit=limit, sort=sort,

swattool/review.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
from .bugzilla import Bugzilla
1616
from . import utils
1717
from . import userdata
18-
from .webrequests import RefreshPolicy
1918

2019
logger = logging.getLogger(__name__)
2120

@@ -340,7 +339,7 @@ def get_new_reviews() -> dict[tuple[swatbotrest.TriageStatus, Any],
340339
continue
341340

342341
def is_pending(failure_id):
343-
r = RefreshPolicy.FORCE
342+
r = swatbotrest.RefreshPolicy.FORCE
344343
failure = swatbotrest.get_stepfailure(failure_id,
345344
refresh_override=r)
346345
return failure['attributes']['triage'] == 0

swattool/swatbotrest.py

+68-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python3
22

3-
"""Interraction with the swatbot Django server."""
3+
"""Interaction with the swatbot Django server."""
44

55
import enum
66
import json
@@ -10,7 +10,7 @@
1010
import requests
1111

1212
from . import utils
13-
from .webrequests import RefreshPolicy, Session
13+
from .webrequests import Session
1414

1515
logger = logging.getLogger(__name__)
1616

@@ -19,6 +19,67 @@
1919
REST_BASE_URL = f"{BASE_URL}/rest"
2020

2121

22+
class RefreshPolicy(enum.Enum):
23+
"""A swatbot cache refresh policy."""
24+
25+
NO = enum.auto()
26+
FORCE = enum.auto()
27+
FORCE_FAILURES = enum.auto()
28+
AUTO = enum.auto()
29+
30+
31+
class RefreshManager:
32+
"""A refresh manager for the swatbot REST API."""
33+
34+
_instance = None
35+
36+
FAILURES_AUTO_REFRESH_S = 60 * 60 * 4
37+
AUTO_REFRESH_S = 60 * 60 * 24 * 30
38+
39+
# pylint: disable=duplicate-code
40+
# pylint complains because of duplicate code in singleton init. We might do
41+
# better, but keep it that way for now.
42+
def __new__(cls, *args, **kwargs):
43+
if not isinstance(cls._instance, cls):
44+
cls._instance = super().__new__(cls, *args, **kwargs)
45+
cls._instance.initialized = False
46+
return cls._instance
47+
48+
def __init__(self):
49+
if self._instance.initialized:
50+
return
51+
52+
self.refresh_policy = RefreshPolicy.AUTO
53+
54+
self._instance.initialized = True
55+
56+
def set_policy(self, policy: RefreshPolicy):
57+
"""Set the global refresh policy."""
58+
self.refresh_policy = policy
59+
60+
def set_policy_by_name(self, policy_name: str):
61+
"""Set the global refresh policy from policy name."""
62+
self.set_policy(RefreshPolicy[policy_name.upper()])
63+
64+
def get_refresh_max_age(self,
65+
refresh_override: Optional[RefreshPolicy] = None,
66+
failures: bool = False
67+
) -> int:
68+
"""Get the maximum age before refresh for a given policy."""
69+
policy = refresh_override if refresh_override else self.refresh_policy
70+
if policy == RefreshPolicy.FORCE_FAILURES:
71+
policy = RefreshPolicy.FORCE if failures else RefreshPolicy.AUTO
72+
73+
if policy == RefreshPolicy.FORCE:
74+
return 0
75+
if policy == RefreshPolicy.NO:
76+
return -1
77+
78+
if failures:
79+
return self.FAILURES_AUTO_REFRESH_S
80+
return self.AUTO_REFRESH_S
81+
82+
2283
class TriageStatus(enum.IntEnum):
2384
"""A status to set on a failure."""
2485

@@ -35,10 +96,6 @@ def from_str(status: str) -> 'TriageStatus':
3596
CANCELLED = 5
3697

3798

38-
FAILURES_AUTO_REFRESH_S = 60 * 60 * 4
39-
AUTO_REFRESH_S = 60 * 60 * 24 * 30
40-
41-
4299
def _get_csrftoken() -> str:
43100
return Session().session.cookies['csrftoken']
44101

@@ -83,15 +140,14 @@ def _get_json(path: str, max_cache_age: int = -1):
83140

84141
def get_build(buildid: int, refresh_override: Optional[RefreshPolicy] = None):
85142
"""Get info on a given build."""
86-
maxage = Session().refresh_policy_max_age(AUTO_REFRESH_S, refresh_override)
143+
maxage = RefreshManager().get_refresh_max_age(refresh_override)
87144
return _get_json(f"/build/{buildid}/", maxage)['data']
88145

89146

90147
def get_build_collection(collectionid: int, refresh_override:
91148
Optional[RefreshPolicy] = None):
92149
"""Get info on a given build collection."""
93-
maxage = Session().refresh_policy_max_age(AUTO_REFRESH_S,
94-
refresh_override)
150+
maxage = RefreshManager().get_refresh_max_age(refresh_override)
95151
return _get_json(f"/buildcollection/{collectionid}/", maxage)['data']
96152

97153

@@ -106,16 +162,15 @@ def invalidate_stepfailures_cache():
106162

107163
def get_stepfailures(refresh_override: Optional[RefreshPolicy] = None):
108164
"""Get info on all failures."""
109-
maxage = Session().refresh_policy_max_age(FAILURES_AUTO_REFRESH_S,
110-
refresh_override)
165+
maxage = RefreshManager().get_refresh_max_age(refresh_override,
166+
failures=True)
111167
return _get_json("/stepfailure/", maxage)['data']
112168

113169

114170
def get_stepfailure(failureid: int,
115171
refresh_override: Optional[RefreshPolicy] = None):
116172
"""Get info on a given failure."""
117-
maxage = Session().refresh_policy_max_age(FAILURES_AUTO_REFRESH_S,
118-
refresh_override)
173+
maxage = RefreshManager().get_refresh_max_age(refresh_override)
119174
return _get_json(f"/stepfailure/{failureid}/", maxage)['data']
120175

121176

swattool/webrequests.py

+1-26
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22

33
"""Wrapper for requests module with cookies persistence and basic cache."""
44

5-
import enum
65
import hashlib
76
import logging
87
import pathlib
98
import pickle
109
import time
11-
from typing import Any, Optional
10+
from typing import Any
1211

1312
import requests
1413

@@ -19,14 +18,6 @@
1918
COOKIESFILE = utils.DATADIR / 'cookies'
2019

2120

22-
class RefreshPolicy(enum.Enum):
23-
"""A cache refresh policy."""
24-
25-
NO = enum.auto()
26-
FORCE = enum.auto()
27-
AUTO = enum.auto()
28-
29-
3021
class Session:
3122
"""A session with persistent cookies."""
3223

@@ -43,29 +34,13 @@ def __init__(self):
4334
return
4435

4536
self.session = requests.Session()
46-
self.refresh_policy = RefreshPolicy.AUTO
4737

4838
if COOKIESFILE.exists():
4939
with COOKIESFILE.open('rb') as file:
5040
self.session.cookies.update(pickle.load(file))
5141

5242
self._instance.initialized = True
5343

54-
def set_refresh_policy(self, policy: RefreshPolicy):
55-
"""Set the global refresh policy."""
56-
self.refresh_policy = policy
57-
58-
def refresh_policy_max_age(self, auto: int,
59-
refresh_override: Optional[RefreshPolicy] = None
60-
) -> int:
61-
"""Get the maximum age before refresh for a given policy."""
62-
policy = refresh_override if refresh_override else self.refresh_policy
63-
if policy == RefreshPolicy.FORCE:
64-
return 0
65-
if policy == RefreshPolicy.NO:
66-
return -1
67-
return auto
68-
6944
def save_cookies(self):
7045
"""Save cookies so they can be used for later sessions."""
7146
COOKIESFILE.parent.mkdir(parents=True, exist_ok=True)

0 commit comments

Comments
 (0)