Paramètre window interval sur job Documentum

De EjnTricks
Révision de 28 août 2014 à 10:53 par Etienne (discussion | contributions)

(diff) ← Version précédente | Voir la version courante (diff) | Version suivante → (diff)

Dans les jobs standards de Documentum, il n'est pas rare de constater l'argument -window_interval XXX, où XXX est un nombre, dans les paramètres des jobs. Cet argument permet de restreindre la plage horaire d'exécution des jobs. Mais sans une bonne compréhension de son utilisation, cet argument devient rapidement une contrainte quand il est souhaité d'exécuter un job. Cependant, cet argument n'est pas interprété par le serveur en lui même, et doit être pris en compte dans le code de la méthode. Dans le cadre d'une méthode serveur personnalisée, il faudra reproduire la fonctionnalité dans le code de celle-ci.

Dans le cadre de cet article, le job dm_LogPurge sera pris pour exemple.


Hand-icon.png Votre avis

Nobody voted on this yet

 You need to enable JavaScript to vote


Study icon.png Analyse plannification

Déclaration job

Un exemple de déclaration du job dm_LogPurge est le suivant:

API> retrieve,c,dm_job where object_name='dm_LogPurge'
...
080000018000035d
API> dump,c,l
...
USER ATTRIBUTES

  object_name                     : dm_LogPurge
  title                           : Docbase
  subject                         : Removes outdated server/session, and job/method logs
  authors                       []: <none>
  keywords                      []: <none>
  resolution_label                :
  owner_name                      : dmadmin
  owner_permit                    : 7
  group_name                      : docu
  group_permit                    : 1
  world_permit                    : 1
  log_entry                       :
  acl_domain                      : docbase01
  acl_name                        : dm_acl_superusers
  language_code                   :
  method_name                     : dm_LogPurge
  method_arguments             [0]: -window_interval 120
                               [1]: -queueperson
                               [2]: -cutoff_days 30
  pass_standard_arguments         : T
  start_date                      : 11/14/2012 8:30:00 PM
  expiration_date                 : 11/14/2020 8:30:00 PM
  max_iterations                  : 0
  run_interval                    : 1
  run_mode                        : 3
  is_inactive                     : T
  inactivate_after_failure        : F
  target_server                   : docbase01.docbase01@win-mcnoeo9a2pt
  method_trace_level              : 0
  run_now                         : F
  method_data                   []: <none>

SYSTEM ATTRIBUTES

  r_object_type                   : dm_job
  r_creation_date                 : 11/14/2012 4:49:11 PM
  r_modify_date                   : 11/14/2012 4:49:11 PM
  r_modifier                      : dmadmin
  r_access_date                   : nulldate
  r_composite_id                []: <none>
  r_composite_label             []: <none>
  r_component_label             []: <none>
  r_order_no                    []: <none>
  r_link_cnt                      : 0
  r_link_high_cnt                 : 0
  r_assembled_from_id             : 0000000000000000
  r_frzn_assembly_cnt             : 0
  r_has_frzn_assembly             : F
  r_is_virtual_doc                : 0
  r_page_cnt                      : 0
  r_content_size                  : 0
  r_lock_owner                    :
  r_lock_date                     : nulldate
  r_lock_machine                  :
  r_version_label              [0]: 1.0
                               [1]: CURRENT
  r_immutable_flag                : F
  r_frozen_flag                   : F
  r_has_events                    : F
  r_creator_name                  : dmadmin
  r_is_public                     : F
  r_policy_id                     : 0000000000000000
  r_resume_state                  : 0
  r_current_state                 : 0
  r_alias_set_id                  : 0000000000000000
  r_full_content_size             : 0
  r_aspect_name                 []: <none>
  r_object_id                     : 080000018000035d

APPLICATION ATTRIBUTES

  a_application_type              :
  a_status                        :
  a_is_hidden                     : F
  a_retention_date                : nulldate
  a_archive                       : F
  a_compound_architecture         :
  a_link_resolved                 : F
  a_content_type                  :
  a_full_text                     : T
  a_storage_type                  :
  a_special_app                   :
  a_effective_date              []: <none>
  a_expiration_date             []: <none>
  a_publish_formats             []: <none>
  a_effective_label             []: <none>
  a_effective_flag              []: <none>
  a_category                      :
  a_is_template                   : F
  a_controlling_app               :
  a_extended_properties         []: <none>
  a_is_signed                     : F
  a_last_review_date              : nulldate
  a_continuation_interval         : 0
  a_next_continuation             : nulldate
  a_is_continued                  : F
  a_last_invocation               : nulldate
  a_last_completion               : nulldate
  a_last_return_code              : 0
  a_last_process_id               : 0
  a_last_document_id              : 0000000000000000
  a_iterations                    : 0
  a_current_status                :
  a_next_invocation               : 11/14/2012 8:30:00 PM

INTERNAL ATTRIBUTES

  i_is_deleted                    : F
  i_reference_cnt                 : 1
  i_has_folder                    : T
  i_folder_id                  [0]: 0b0000018000034a
  i_contents_id                   : 0000000000000000
  i_cabinet_id                    : 0c00000180000106
  i_antecedent_id                 : 0000000000000000
  i_chronicle_id                  : 080000018000035d
  i_latest_flag                   : T
  i_branch_cnt                    : 0
  i_direct_dsc                    : F
  i_is_reference                  : F
  i_retain_until                  : nulldate
  i_retainer_id                 []: <none>
  i_partition                     : 0
  i_is_replica                    : F
  i_vstamp                        : 0

Le job exécute donc la méthode dm_LogPurge.

Déclaration méthode

La déclaration de la méthode va permettre d'identifier le fichier contenant le code source.

API> retrieve,c,dm_method where object_name='dm_LogPurge'
...
1000000180000367
API> dump,c,l
...
USER ATTRIBUTES

  object_name                     : dm_LogPurge
  title                           :
  subject                         :
  authors                       []: <none>
  keywords                      []: <none>
  resolution_label                :
  owner_name                      : dmadmin
  owner_permit                    : 7
  group_name                      : docu
  group_permit                    : 1
  world_permit                    : 1
  log_entry                       :
  acl_domain                      : docbase01
  acl_name                        : dm_acl_superusers
  language_code                   :
  method_verb                     : .\dmbasic -f..\install\admin\mthd2.ebs -eLogPurge
  method_args                   []: <none>
  timeout_min                     : 30
  timeout_max                     : 604800
  timeout_default                 : 604800
  launch_direct                   : F
  launch_async                    : F
  trace_launch                    : F
  run_as_server                   : T
  use_method_content              : F
  method_type                     : dmbasic
  use_method_server               : F
  success_return_codes          []: <none>
  success_status                  :
  is_restartable                  : F

SYSTEM ATTRIBUTES

  r_object_type                   : dm_method
  r_creation_date                 : 11/14/2012 4:49:11 PM
  r_modify_date                   : 11/14/2012 4:49:11 PM
  r_modifier                      : dmadmin
  r_access_date                   : nulldate
  r_composite_id                []: <none>
  r_composite_label             []: <none>
  r_component_label             []: <none>
  r_order_no                    []: <none>
  r_link_cnt                      : 0
  r_link_high_cnt                 : 0
  r_assembled_from_id             : 0000000000000000
  r_frzn_assembly_cnt             : 0
  r_has_frzn_assembly             : F
  r_is_virtual_doc                : 0
  r_page_cnt                      : 0
  r_content_size                  : 0
  r_lock_owner                    :
  r_lock_date                     : nulldate
  r_lock_machine                  :
  r_version_label              [0]: 1.0
                               [1]: CURRENT
  r_immutable_flag                : F
  r_frozen_flag                   : F
  r_has_events                    : F
  r_creator_name                  : dmadmin
  r_is_public                     : F
  r_policy_id                     : 0000000000000000
  r_resume_state                  : 0
  r_current_state                 : 0
  r_alias_set_id                  : 0000000000000000
  r_full_content_size             : 0
  r_aspect_name                 []: <none>
  r_object_id                     : 1000000180000367

APPLICATION ATTRIBUTES

  a_application_type              :
  a_status                        :
  a_is_hidden                     : F
  a_retention_date                : nulldate
  a_archive                       : F
  a_compound_architecture         :
  a_link_resolved                 : F
  a_content_type                  :
  a_full_text                     : T
  a_storage_type                  :
  a_special_app                   : 1.0.0
  a_effective_date              []: <none>
  a_expiration_date             []: <none>
  a_publish_formats             []: <none>
  a_effective_label             []: <none>
  a_effective_flag              []: <none>
  a_category                      :
  a_is_template                   : F
  a_controlling_app               :
  a_extended_properties         []: <none>
  a_is_signed                     : F
  a_last_review_date              : nulldate

INTERNAL ATTRIBUTES

  i_is_deleted                    : F
  i_reference_cnt                 : 1
  i_has_folder                    : T
  i_folder_id                  [0]: 0b00000180000108
  i_contents_id                   : 0000000000000000
  i_cabinet_id                    : 0c00000180000106
  i_antecedent_id                 : 0000000000000000
  i_chronicle_id                  : 1000000180000367
  i_latest_flag                   : T
  i_branch_cnt                    : 0
  i_direct_dsc                    : F
  i_is_reference                  : F
  i_retain_until                  : nulldate
  i_retainer_id                 []: <none>
  i_partition                     : 0
  i_is_replica                    : F
  i_vstamp                        : 0

La valeur de l'attribut method_veb est .\dmbasic -f..\install\admin\mthd2.ebs -eLogPurge permettant d'identifier:

Paramètre Valeur
Emplacement code source. ..\install\admin\mthd2.ebs par rapport aux répertoire d'exécution.
Point d'entrée de la méthode. fonction LogPurge.

Le fichier mthd2.ebs est utilisé par plusieurs méthodes serveur:

  • dm_AuditMgt
  • dm_LogPurge
  • dm_QueueMgt
  • dm_SwapInfo

Donc, le contenu du fichier est assez conséquent.


Study icon.png Analyse utilisation de l'argument

Cette analyse est réalisée sur une version 6.7 SP1, mais cela s'applique à l'ensemble des version.

Message d'annulation

Lorsque l'exécution du job n'est pas réalisée dans la restriction, mise en place avec window_interval, le statut stocké dans l'attribut a_current_status de l'objet dm_job est similaire au message suivant:

 a_current_status                : LogPurge Tool was aborted at 12/26/2013 23:21:09.  View the job's report for details.

La consultation de la log associée, identifié dans l'attribut a_last_document_id, n'apporte pas tellement d'informations supplémentaires.

Connected To docbase01.docbase01
There was a problem, and the program aborted...
LogPurge Tool was aborted at 12/26/2013 23:21:09.  View the job's report for details.
Calling SetJobStatus function...

 
--- Start E:\Documentum\dba\log\00000001\sysadmin\LogPurgeDoc.txt report output ----
LogPurge Report For DocBase docbase01 As Of 12/26/2013 23:21:09
   
Aborting--Job can't run in it's time window, please check the window_interval argument which is currently set to               120 
Report End  12/26/2013 23:21:09
--- End E:\Documentum\dba\log\00000001\sysadmin\LogPurgeDoc.txt report output ---

Nous pouvons regretter la non présence d'une précision sur l'intervalle de temps disponible, seule la valeur de window_interval étant rappelée.

Méthode LogPurge

Dans les première instruction de la méthode, le code suivant est constaté:

  If CheckWindow(JobID) = 0 Then
    ran_ok = "false"
    Call CloseOut(start_date,ran_ok,JobName,JobID,ResultDoc,ResultPath,MethodTraceLevel)
    ret% = dmAPIExec("disconnect,c")
    Exit Sub
  End If

Le nom de la fonction est suffisant parlant pour s'attendre à ce que l'argument window_interval soit pris en compte. Il aurait également été possible de rechercher dans le code le nom de l'argument.

Fonction CheckWindow

L'utilisation du paramètre est pris en compte dans cette fonction:

Function CheckWindow(JobID As String) As Integer
  Dim LowerDate As date, UpperDate as date, InvocationToday as date
  Dim WindowInterval As Long, NextInvocation As Date
  Dim theHour as string, theMinute as string
  Dim theMode as string
  
  On Error Goto DBerrorCatch
  CheckWindow = 1
  WindowInterval = CLng(GetJobArg(JobID, "-window_interval"))
  
  If WindowInterval = 99999 Then
     Print #2, "The mandatory -window_interval argument was not found"
     CheckWindow = 0
     Exit Function
  End If
  
  ' If run_mode is minutes or hours [1 or 2] then we don't care about window_interval
  theMode = dmAPIGet("get,c," & JobID & ",run_mode")
  If Cint(theMode) < 3 Then
     Exit Function
  End If
  
  NextInvocation = CDate(dmAPIGet("get,c," & JobID & ",a_next_invocation"))
  
  theHour = DatePart("h", NextInvocation)
  theMinute = DatePart("n", NextInvocation)
  
  InvocationToday = dmNow(date & " " & theHour & ":" & theMinute & ":0")
  
  LowerDate = DateAdd("n", -WindowInterval, InvocationToday)
  UpperDate = DateAdd("n", WindowInterval, InvocationToday)
  
  ' how far apart is date & " " & time$ from scheduled date
  howfarApart& = Clng(datediff("d", InvocationToday, dmNow(date & " " & time$)))
  
  ' is date & " " & time$ prior to UpperDate?
  If dmNow(date & " " & time$) < UpperDate Then howfarApart& = howfarApart& - 1
  If howfarApart& < 0 Then howfarApart& = howfarApart& + 1
  
  ' recompute lower and upper dates
  LowerDate = DateAdd("d", howfarApart&, LowerDate)
  UpperDate = DateAdd("d", howfarApart&, UpperDate)
  
  ' verify that we are within the window
  If LowerDate <= Cdate(dmNow(date & " " & time$)) AND Cdate(dmNow(date & " " & time$)) <= UpperDate  Then
    Exit Function
  Else
    ' if the next invocation time has already passed, we need to advance it
    If InvocationToday < CDate(dmNow(date & " " & time$)) Then
      ' make sure howfarApart is at least 1
      ' this prevents us from setting a_next_invocation to be in the past
      If howfarApart& <= 0 Then
        howfarApart& = 1
      End If
      
      InvocationToday = DateAdd("d", howfarApart&, InvocationToday)
    End If
    
    ret% = dmAPISet("set,c," & JobID & ",a_next_invocation", Format$(InvocationToday, "mm/dd/yyyy hh:nn:ss"))
    ret% = dmAPIExec("save,c," & JobID)
    Print #2, "Aborting--Job can't run in it's time window, please check " & _ 
              "the window_interval argument which is currently set to ", WindowInterval
    CheckWindow = 0
  End If
  Exit Function
DBerrorCatch:
  Print Err, Error(Err)
  'Resume Next
End Function

Heure d'exécution

Les instructions suivantes vont permettre d'extraire l'heure et les minutes de la prochaine exécution du job, récupérés à partir de l'attribut a_next_invocation, quelque soit le jour:

  NextInvocation = CDate(dmAPIGet("get,c," & JobID & ",a_next_invocation"))
  
  theHour = DatePart("h", NextInvocation)
  theMinute = DatePart("n", NextInvocation)

Calcul de la fenêtre

Ces informations sont ajoutées au jour en cours, retourné par la fonction date, donnant l'instant d'exécution pour le jour en cours:

  InvocationToday = dmNow(date & " " & theHour & ":" & theMinute & ":0")

L'intervalle est ensuite ajouté à cette nouvelle date en négatif et positif, la valeur utilisée correspondant à des minutes:

  LowerDate = DateAdd("n", -WindowInterval, InvocationToday)
  UpperDate = DateAdd("n", WindowInterval, InvocationToday)

Ceci permet de calculer la fenêtre de temps durant laquelle le job peut être exécutée.

Les calculs suivants sont les plus complexes et vont permettre que les dates calculées correspondent bien au jour en cours:

  ' how far apart is date & " " & time$ from scheduled date
  howfarApart& = Clng(datediff("d", InvocationToday, dmNow(date & " " & time$)))
  
  ' is date & " " & time$ prior to UpperDate?
  If dmNow(date & " " & time$) < UpperDate Then howfarApart& = howfarApart& - 1
  If howfarApart& < 0 Then howfarApart& = howfarApart& + 1
  
  ' recompute lower and upper dates
  LowerDate = DateAdd("d", howfarApart&, LowerDate)
  UpperDate = DateAdd("d", howfarApart&, UpperDate)

Cela permet d'affiner la fenêtre d'exécution calculée.

1er exemple: a_next_invocation: YYYY/MM/DD 01:00:00 window_interval: 180 (minutes, soit 3h)

La fenêtre d'exécution calculée sera donc:

  • Limite basse: AUJOURD'HUI 22:00:00
  • Limite hausse: (AUJOURD'HUI + 1) 04:00:00

2ème exemple: a_next_invocation: YYYY/MM/DD 23:00:00 window_interval: 180 (minutes, soit 3h)

La fenêtre d'exécution calculée sera donc:

  • Limite basse: AUJOURD'HUI 20:00:00
  • Limite hausse: (AUJOURD'HUI + 1) 02:00:00

3ème exemple: a_next_invocation: YYYY/MM/DD 15:00:00 window_interval: 180 (minutes, soit 3h)

La fenêtre d'exécution calculée sera donc:

  • Limite basse: AUJOURD'HUI 12:00:00
  • Limite hausse: AUJOURD'HUI 18:00:00

Contrôle de la fenêtre d'exécution

Une fois les dates inférieurs et supérieures calculées, il est contrôler que l'heure courante se situe bien entre les deux bornes.

  ' verify that we are within the window
  If LowerDate <= Cdate(dmNow(date & " " & time$)) AND Cdate(dmNow(date & " " & time$)) <= UpperDate  Then
    Exit Function
  Else
    ' if the next invocation time has already passed, we need to advance it
    If InvocationToday < CDate(dmNow(date & " " & time$)) Then
      ' make sure howfarApart is at least 1
      ' this prevents us from setting a_next_invocation to be in the past
      If howfarApart& <= 0 Then
        howfarApart& = 1
      End If
      
      InvocationToday = DateAdd("d", howfarApart&, InvocationToday)
    End If
    
    ret% = dmAPISet("set,c," & JobID & ",a_next_invocation", Format$(InvocationToday, "mm/dd/yyyy hh:nn:ss"))
    ret% = dmAPIExec("save,c," & JobID)
    Print #2, "Aborting--Job can't run in it's time window, please check " & _ 
              "the window_interval argument which is currently set to ", WindowInterval
    CheckWindow = 0
  End If

Si tel est le cas, alors la fonction est quittée sans modifier la valeur initialisée à 1, indiquant que la fenêtre est validée. Si tel n'est pas le cas, elle sera quittée avec la valeur 0, indiquant la non validation, et la valeur de l'attribut a_next_invocation est mise à jour, en s'assurant que la date spécifiée n'est pas dans le passée.

En résumé, il faut juste prendre les heures de la prochaine d'exécution, y supprimer et ajouter les heures et cela donne la fenêtre d'exécution.

Cas particulier

Comme indiqué en commentaire au début de la fonction, tout ce contrôle n'est pas utilisé si l'intervalle d'exécution est en minutes ou heures sur le job.

  ' If run_mode is minutes or hours [1 or 2] then we don't care about window_interval
  theMode = dmAPIGet("get,c," & JobID & ",run_mode")
  If Cint(theMode) < 3 Then
     Exit Function
  End If


Process-Icon.png Forcer l'exécution

Il arrive que l'on souhaite exécuter le job malgré cette fenêtre d'exécution. Comme il est impossible de supprimer l'argument window_interval, puisqu'il est contrôlé lors de l'exécution de la méthode, il est nécessaire de travailler sur cette fenêtre d'exécution.

Modification de a_next_invocation

La première possibilité est de modifier la valeur de l'attribut a_next_invocation sur le job afin de spécifier une heure qui permettra d'avoir une limite basse et haute qui va encadrer l'heure d'exécution.

Exemple: a_next_invocation: YYYY/MM/DD 01:00:00 window_interval: 180 (minutes, soit 3h)

L'heure courante étant 11:00:00, il suffira de modifier la valeur de a_next_invocation avec une heure entre :

  • 08:00:00 qui donnera une fenêtre d'exécution entre 05:00:00 et 11:00:00
  • 14:00:00 qui donnera une fenêtre d'exécution entre 11:00:00 et 17:00:00

Cependant, cela aura également pour effet de modifier la valeur de a_next_invocation, après exécution du job, avec l'heure modifiée. Il faudra penser à ré initialiser la valeur avec l'heure originale.

Modification de window_interval

La deuxième possibilité est de modifier la valeur de l'argument window_interval afin d'agrandir la fenêtre d'exécution. Afin d'éviter les calculs, le plus simple est de spécifier -window_interval 1440 dans l'attribut method_arguments du job. En effet, 1440 correspondant à 24 heures, cela permet d'avoir une fenêtre d'exécution sur une journée complète avant et après la date de la prochaine exécution. Le contrôle de la fenêtre d'exécution sera alors toujours valide.

Il faudra penser à ré initialiser la valeur avec l'interval original.