Package coprs :: Package logic :: Module batches_logic
[hide private]
[frames] | no frames]

Source Code for Module coprs.logic.batches_logic

  1  """ 
  2  Methods for working with build Batches. 
  3  """ 
  4   
  5  import anytree 
  6   
  7  from coprs import db 
  8  from coprs.helpers import WorkList 
  9  from coprs.models import Batch, Build 
 10  from coprs.exceptions import BadRequest 
 11  import coprs.logic.builds_logic as bl 
12 13 14 -class BatchesLogic:
15 """ Batch logic entrypoint """ 16 @classmethod
17 - def get_batch_or_create(cls, build_id, requestor, modify=False):
18 """ 19 Put the build into a new batch, and return the batch. If the build is 20 already assigned to any batch, do nothing and return the batch. 21 22 Locks the build for updates, may block! 23 """ 24 25 # We don't want to create a new batch if one already exists, but there's 26 # the concurrency problem so we need to lock the build instance for 27 # writing. 28 build = db.session.query(Build).with_for_update().get(build_id) 29 if not build: 30 raise BadRequest("Build {} doesn't exist".format(build_id)) 31 32 # Somewhat pedantically, we _should_ lock the batch (if exists) 33 # here because the query for 'build.finished' and 34 # 'build.batch.finished' is a bit racy (backend workers may 35 # asynchronously make the build/batch finished, and we may still 36 # assign some new build to a just finished batch). 37 error = build.batching_user_error(requestor, modify) 38 if error: 39 raise BadRequest(error) 40 41 if build.batch: 42 return build.batch 43 44 batch = Batch() 45 db.session.add(batch) 46 build.batch = batch 47 return batch
48 49 @staticmethod
50 - def pending_batches():
51 """ 52 Query for all still not-finished batches, order by id ASC 53 """ 54 batches = set() 55 query = bl.BuildsLogic.processing_builds() 56 for build in query.all(): 57 if build.batch: 58 batches.add(build.batch) 59 return batches
60 61 @classmethod
62 - def pending_batch_trees(cls):
63 """ 64 Get all the currently processing batches, together with all the 65 dependency batches which are already finished -- and keep them ordered 66 in list based on theirs ID and dependencies. 67 """ 68 roots = [] 69 node_map = {} 70 def get_mapped_node(batch): 71 if batch.id in node_map: 72 return node_map[batch.id] 73 node_map[batch.id] = anytree.Node(batch) 74 return node_map[batch.id]
75 76 # go through all the batches transitively 77 pending_batches = cls.pending_batches() 78 wl = WorkList(pending_batches) 79 while not wl.empty: 80 batch = wl.pop() 81 node = get_mapped_node(batch) 82 if batch.blocked_by_id: 83 parent_node = get_mapped_node(batch.blocked_by) 84 node.parent = parent_node 85 wl.schedule(batch.blocked_by) 86 else: 87 roots.append(node) 88 return roots
89 90 @classmethod
91 - def batch_chain(cls, batch_id):
92 """ 93 Return the batch_with batch_id, and all the transitively blocking 94 batches in one list. 95 """ 96 chain = [] 97 batch = Batch.query.get(batch_id) 98 while batch: 99 chain.append(batch) 100 batch = batch.blocked_by 101 return chain
102 103 # STILL PENDING 104 # ============= 105 # => some builds are: waiting, pending, starting, running, importing 106 # => the rest is: succeeded/failed 107 # 108 # SUCCEEDED 109 # ========= 110 # => all builds succeeded 111 # 112 # FAILED, BUT FIXABLE 113 # =================== 114 # => all builds are succeeded or failed 115 # => timeout is OK: last ended_on is >= time.time() - deadline 116 # 117 # FAILED 118 # ====== 119 # => some builds failed 120 # => timeout is out 121