Support relative priority of node requests

The launcher now processes node requests in relative priority
order.  This relies on the new node request cache because the
relative priority field may be updated at any time by the
requestor.

Needed-By: https://review.openstack.org/615356
Change-Id: If893c34c6652b9649bfb6f1d9f7b942c549c98b4
This commit is contained in:
James E. Blair 2018-11-29 08:33:24 -08:00
parent 40162102a7
commit 854f638e35
3 changed files with 45 additions and 3 deletions

View File

@ -164,7 +164,15 @@ class PoolWorker(threading.Thread):
if provider.max_concurrency == 0:
return
for req_id in self.zk.getNodeRequests():
# Sort requests by queue priority, then, for all requests at
# the same priority, use the relative_priority field to
# further sort, then finally, the submission order.
requests = list(self.zk.nodeRequestIterator())
requests.sort(key=lambda r: (r.id.split('-')[0],
r.relative_priority,
r.id.split('-')[1]))
for req in requests:
if self.paused_handler:
return
@ -182,7 +190,7 @@ class PoolWorker(threading.Thread):
active_threads, provider.max_concurrency)
return
req = self.zk.getNodeRequest(req_id)
req = self.zk.getNodeRequest(req.id)
if not req:
continue

View File

@ -1792,3 +1792,33 @@ class TestLauncher(tests.DBTestCase):
req3 = self.waitForNodeRequest(req3)
self.assertEqual(req3.state, zk.FAILED)
def test_request_order(self):
"""Test that requests are handled in sorted order"""
configfile = self.setup_config('node_no_min_ready.yaml')
self.useBuilder(configfile)
image = self.waitForImage('fake-provider', 'fake-image')
self.assertEqual(image.username, 'zuul')
req1 = zk.NodeRequest()
req1.state = zk.REQUESTED
req1.node_types.append('fake-label')
req1.relative_priority = 2
self.zk.storeNodeRequest(req1)
req2 = zk.NodeRequest()
req2.state = zk.REQUESTED
req2.node_types.append('fake-label')
req2.relative_priority = 1
self.zk.storeNodeRequest(req2)
pool = self.useNodepool(configfile, watermark_sleep=1)
pool.start()
req2 = self.waitForNodeRequest(req2)
self.assertEqual(req2.state, zk.FULFILLED)
req1 = self.waitForNodeRequest(req1)
self.assertEqual(req1.state, zk.FULFILLED)
self.assertTrue(req2.id > req1.id)
self.assertTrue(req2.state_time < req1.state_time)

View File

@ -433,6 +433,7 @@ class NodeRequest(BaseModel):
self.nodes = []
self.reuse = True
self.requestor = None
self.relative_priority = 0
def __repr__(self):
d = self.toDict()
@ -447,7 +448,8 @@ class NodeRequest(BaseModel):
self.node_types == other.node_types and
self.nodes == other.nodes and
self.reuse == other.reuse and
self.requestor == other.requestor)
self.requestor == other.requestor and
self.relative_priority == other.relative_priority)
else:
return False
@ -461,6 +463,7 @@ class NodeRequest(BaseModel):
d['nodes'] = self.nodes
d['reuse'] = self.reuse
d['requestor'] = self.requestor
d['relative_priority'] = self.relative_priority
return d
@staticmethod
@ -485,6 +488,7 @@ class NodeRequest(BaseModel):
self.nodes = d.get('nodes', [])
self.reuse = d.get('reuse', True)
self.requestor = d.get('requestor')
self.relative_priority = d.get('relative_priority', 0)
class Node(BaseModel):