1616import uuid
1717from datetime import datetime
1818from functools import reduce
19- from typing import Dict , List
19+ from typing import Dict , List , Tuple
2020
2121from reana_commons .config import (
2222 MQ_MAX_PRIORITY ,
5454 DB_SECRET_KEY ,
5555 DEFAULT_QUOTA_LIMITS ,
5656 DEFAULT_QUOTA_RESOURCES ,
57- LIMIT_RESTARTS ,
5857 WORKFLOW_TERMINATION_QUOTA_UPDATE_POLICY ,
5958)
6059from reana_db .utils import (
6160 build_workspace_path ,
6261 store_workflow_disk_quota ,
62+ split_run_number ,
6363 update_users_cpu_quota ,
6464 update_users_disk_quota ,
6565 update_workflow_cpu_quota ,
@@ -459,7 +459,8 @@ class Workflow(Base, Timestamp, QuotaBase):
459459 run_started_at = Column (DateTime )
460460 run_finished_at = Column (DateTime )
461461 run_stopped_at = Column (DateTime )
462- _run_number = Column ("run_number" , Float )
462+ generation_number = Column (Integer )
463+ restart_number = Column (Integer , default = 0 )
463464 job_progress = Column (JSONType , default = dict )
464465 workspace_path = Column (String )
465466 restart = Column (Boolean , default = False )
@@ -487,7 +488,11 @@ class Workflow(Base, Timestamp, QuotaBase):
487488
488489 __table_args__ = (
489490 UniqueConstraint (
490- "name" , "owner_id" , "run_number" , name = "_user_workflow_run_uc"
491+ "name" ,
492+ "owner_id" ,
493+ "generation_number" ,
494+ "restart_number" ,
495+ name = "_user_workflow_run_uc" ,
491496 ),
492497 {"schema" : "__reana" },
493498 )
@@ -527,7 +532,9 @@ def __init__(
527532 self .git_repo = git_repo
528533 self .git_provider = git_provider
529534 self .restart = restart
530- self ._run_number = self .assign_run_number (run_number )
535+ self .generation_number , self .restart_number = self .get_new_run_number (
536+ run_number
537+ )
531538 self .workspace_path = workspace_path or build_workspace_path (
532539 self .owner_id , self .id_
533540 )
@@ -538,53 +545,65 @@ def __repr__(self):
538545 return "<Workflow %r>" % self .id_
539546
540547 @hybrid_property
541- def run_number (self ):
548+ def run_number (self ) -> str :
542549 """Property of run_number."""
543- if self ._run_number .is_integer ():
544- return int (self ._run_number )
545- return self ._run_number
546-
547- @run_number .expression
548- def run_number (cls ):
549- return func .abs (cls ._run_number )
550+ if self .restart_number != 0 :
551+ return f"{ self .generation_number } .{ self .restart_number } "
552+ return str (self .generation_number )
550553
551- def assign_run_number (self , run_number ):
552- """Assing run number."""
554+ def _get_last_workflow (self , run_number ):
555+ """Fetch the last workflow restart given a certain run number."""
553556 from .database import Session
554557
555558 if run_number :
559+ generation_number , restart_number = split_run_number (run_number )
556560 last_workflow = (
557561 Session .query (Workflow )
558562 .filter (
559563 Workflow .name == self .name ,
560- Workflow .run_number >= int (run_number ),
561- Workflow .run_number < int (run_number ) + 1 ,
564+ Workflow .generation_number == generation_number ,
562565 Workflow .owner_id == self .owner_id ,
563566 )
564- .order_by (Workflow .run_number .desc ())
567+ .order_by (
568+ Workflow .generation_number .desc (), Workflow .restart_number .desc ()
569+ )
565570 .first ()
566571 )
567572 else :
568573 last_workflow = (
569574 Session .query (Workflow )
570575 .filter_by (name = self .name , restart = False , owner_id = self .owner_id )
571- .order_by (Workflow .run_number .desc ())
576+ .order_by (
577+ Workflow .generation_number .desc (), Workflow .restart_number .desc ()
578+ )
572579 .first ()
573580 )
574- if last_workflow and self .restart :
575- # FIXME: remove the limit of nine restarts when we fix the way in which
576- # we save `run_number` in the DB
577- num_restarts = round (last_workflow .run_number * 10 ) % 10
578- if num_restarts == LIMIT_RESTARTS :
581+ return last_workflow
582+
583+ def get_new_run_number (self , run_number ) -> Tuple [int , int ]:
584+ """Return the generation and restart numbers for a new workflow.
585+
586+ Return a tuple where the first element is the generation number and the
587+ second element is the restart number.
588+ """
589+ last_workflow = self ._get_last_workflow (run_number )
590+
591+ if not last_workflow :
592+ if self .restart :
579593 raise REANAValidationError (
580- f "Cannot restart a workflow more than { LIMIT_RESTARTS } times "
594+ "Cannot restart a workflow that has not been run before. "
581595 )
582- return round (last_workflow .run_number + 0.1 , 1 )
596+ return 1 , 0 # First generation, no restart
597+
583598 else :
584- if not last_workflow :
585- return 1
599+ if not self .restart :
600+ generation_number = last_workflow .generation_number + 1
601+ restart_number = 0
586602 else :
587- return last_workflow .run_number + 1
603+ generation_number = last_workflow .generation_number
604+ restart_number = last_workflow .restart_number + 1
605+
606+ return generation_number , restart_number
588607
589608 def get_input_parameters (self ):
590609 """Return workflow parameters."""
@@ -604,7 +623,7 @@ def get_owner_access_token(self):
604623
605624 def get_full_workflow_name (self ):
606625 """Return full workflow name including run number."""
607- return "{}.{}" .format (self .name , str ( self .run_number ) )
626+ return "{}.{}" .format (self .name , self .run_number )
608627
609628 def get_workspace_disk_usage (self , summarize = False , search = None ):
610629 """Retrieve disk usage information of a workspace."""
@@ -643,15 +662,13 @@ def get_all_restarts(self):
643662 """Get all the restarts of this workflow, including the original workflow.
644663
645664 Returns all the restarts of this workflow, that is all the workflows that have
646- the same name and the same run number (up to the dot) . This includes the
665+ the same name and the same generation number. This includes the
647666 original workflow, as well as all the following restarts.
648667 """
649- run_number = int (self .run_number )
650668 restarts = Workflow .query .filter (
651669 Workflow .name == self .name ,
652670 Workflow .owner_id == self .owner_id ,
653- Workflow .run_number >= run_number ,
654- Workflow .run_number < run_number + 1 ,
671+ Workflow .generation_number == self .generation_number ,
655672 )
656673 return restarts
657674
0 commit comments