|
1 | 1 | from __future__ import absolute_import
|
2 | 2 |
|
| 3 | +import json |
| 4 | + |
3 | 5 | from ..hubstorage.job import JobMeta as _JobMeta
|
4 | 6 | from ..hubstorage.job import Items as _Items
|
5 | 7 | from ..hubstorage.job import Logs as _Logs
|
@@ -77,6 +79,64 @@ def count(self, spider=None, state=None, has_tag=None, lacks_tag=None,
|
77 | 79 | params['spider'] = self.spider.name
|
78 | 80 | return next(self._project.jobq.apiget(('count',), params=params))
|
79 | 81 |
|
| 82 | + def cancel_jobs(self, keys=None, count=None, **params): |
| 83 | + """Cancel a list of jobs using the keys provided. |
| 84 | +
|
| 85 | + :param keys: (optional) a list of strings containing the job keys in |
| 86 | + the format: <project>/<spider>/<job_id>. |
| 87 | + :param count: (optional) it requires admin access. Used for admins |
| 88 | + to bulk cancel an amount of ``count`` jobs. |
| 89 | +
|
| 90 | + :return: a dict with the amount of jobs cancelled. |
| 91 | + :rtype: :class:`dict` |
| 92 | +
|
| 93 | + Usage: |
| 94 | +
|
| 95 | + - cancel jobs 123 and 321 from project 111 and spiders 222 and 333:: |
| 96 | +
|
| 97 | + >>> project.jobs.cancel_jobs(['111/222/123', '111/333/321']) |
| 98 | + {'count': 2} |
| 99 | +
|
| 100 | + - cancel 100 jobs asynchronously:: |
| 101 | +
|
| 102 | + >>> project.jobs.cancel_jobs(count=100) |
| 103 | + {'count': 100} |
| 104 | + """ |
| 105 | + update_kwargs(params, count=count, keys=keys) |
| 106 | + keys = params.get('keys') |
| 107 | + count = params.get('count') |
| 108 | + |
| 109 | + if keys and count: |
| 110 | + raise ValueError("keys and count can't be defined simultaneously") |
| 111 | + |
| 112 | + elif not keys and not count: |
| 113 | + raise ValueError("keys or count should be defined") |
| 114 | + |
| 115 | + elif keys: |
| 116 | + if not isinstance(keys, list): |
| 117 | + raise ValueError("keys should be a list") |
| 118 | + |
| 119 | + # it raises ValueError if invalid |
| 120 | + keys = [parse_job_key(k) for k in keys] |
| 121 | + |
| 122 | + if not all([key.project_id == self.project_id for key in keys]): |
| 123 | + raise ValueError( |
| 124 | + "all keys should belong to project: %s" % self.project_id |
| 125 | + ) |
| 126 | + |
| 127 | + # change it to the format in which JobQ expects. |
| 128 | + data = [{"key": str(k)} for k in keys] |
| 129 | + |
| 130 | + # may raise BadRequest if JobQ doesn't validate |
| 131 | + return list(self._project.jobq.apipost("cancel", |
| 132 | + data=json.dumps(data)))[0] |
| 133 | + elif count: |
| 134 | + if not isinstance(count, int): |
| 135 | + raise ValueError("count should be an int") |
| 136 | + |
| 137 | + # may raise Forbidden |
| 138 | + return self._project.jobq.apipost("cancel?count=%s" % count) |
| 139 | + |
80 | 140 | def iter(self, count=None, start=None, spider=None, state=None,
|
81 | 141 | has_tag=None, lacks_tag=None, startts=None, endts=None,
|
82 | 142 | meta=None, **params):
|
|
0 commit comments