Paramètre window interval sur job Documentum
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.
Sommaire
Votre avis
Nobody voted on this yet
|
|
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.
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
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.