Le forum (ô combien francophone) des utilisateurs de Powerbuilder.
Bonjour,
Comment peut on expliquer que PB plante lamentablement (en version 8.03)sur le Destroy d'une datastore, alors que celle ci est bien Valid.
A noter que cela se produit dans un "batch" qui tourne tous les jours, mais le problème ne se produit pas heureusement pas tous les jours.
Hors ligne
c'est une variable d'instance ou locale ?
si variable d'instance, tu la detruis à l'évenement close de ta fenetre ?
bref...tout cela est lié avec la gestion de buffer memoire...
Hors ligne
c'est une variable locale, et le pire c'est que si on supprime le destroy, pb détruit l'objet à la fermeture de l'appli en "automatique", mais dans ce cas le batch plante également...effectivement ça ressemble plus à de la gestion mémoire du pc et pourtant, on a rajouté de la mémoire....
Hors ligne
mets la en variable d'instance
tu la crées à l'open de la fenetre
et tu la detruis à l'évenement Close de la fenetre...
tu nous diras s'il y a un changement...
Hors ligne
est-ce que ton datastore est basé sur une datawindow avec l'option rowasneeded ?
hypothèse : tu fais le destroy mais il n'a pas fini de récupérer les résultats, ou encore sur destroy il finit
de récupérer les résultats, s'il y en a trop, out of memory ...
Hors ligne
non la datawindow n'a pas l'option row as needed, et le retrieve est terminé depuis un certain temps lorsque le destroy est executé, et plusieurs traitements ont été fait à partir de la datastore après le retrieve, et puisque le batch s'execute tous les jours, ce n'est pas forcément les jours ou la datastore contient le plus d'enregistrement que cela plante, mais cela ressemble effectivement à un out of memory.
Je vais essayer la méthode de notre ami Pick Ouic en mettant la datastore en variable d'instance, je vous tiendrais au courant.
Hors ligne
bon, mauvaise nouvelle, j'ai mis la datastore en instance , le premier jour pas de problème et cette nuit, même symptome, le destroy n'a pu se faire. Cela n'est pas forcément un problème de volume de données dans la datastore, puisqu'il y a des jour ou ça ne plante pas et il y a plus d'enregistrements. Mystère Mystère.....
Hors ligne
il y a quoi d'autres comme objets ? en dehors de la datastore ?
il y a peut etre une succession d'objets et cie qui declenchent tout ca...
il y a moyen de voir les scripts de ton batch pb ?
Hors ligne
Le batch est une petite appli qui lance une fenetre, et tout le script est fait dans la fenetre. sur le principe c'est historique pour cette appli.
La datastore est mise en variable d'instance dans la fenetre et le destroy est fait dans le close de la fenetre. avec le code suivant :
If IsValid(Ids_factures) then DESTROY Ids_factures invo_batchs.nvuf_ecriture_batchlog("Destroy de lds_facture effectué.") end if
Le code suivant se trouve dans l'évènement Open de la fenetre
long ll_rep, ll_cptr, ll_nbfc, ll_nbfc_non_imp , ll_rowcount int li_error,li_coderet, li_ind_facto string ls_idcodefc, ls_sauv_path, ls_numfac, ls_req datastore lds_controle_client , lds_controle_agence date dt_sysdate boolean lb_retrieve_clt, lb_retrieve_agnce invo_batchs.nvuf_nom_exe("EDITFACT.EXE") //****************************************************************** // Lancement du batch d'edition de facture //****************************************************************** ls_req = "set isolation to dirty read" execute immediate :ls_req ; IF sqlca.sqlcode <> 0 THEN invo_batchs.nvuf_ecriture_batchlog("erreur de dirty read") END IF ll_nbfc = 0 ll_nbfc_non_imp = 0 dt_sysdate = today() //****************************************************************** // intialisation des répertoires de sauvegarde //****************************************************************** ls_sauv_path = ProfileString("batchs.ini", "serveur_sauvegardes", "sauv_dev", "") IF ls_sauv_path = "" OR IsNull(ls_sauv_path) THEN invo_batchs.nvuf_ecriture_batchlog("Erreur de Lecture du batchs.ini / serveur de sauvegarde Espaceprod") RETURN END IF //******************************************************* // Edition de l'état de contrôle d'édition des factures //******************************************************* lds_controle_agence = CREATE datastore lds_controle_agence.dataobject = 'd_t_factures_controle_agence' lds_controle_agence.SetTransObject( sqlca ) li_coderet = lds_controle_agence.Retrieve( dt_sysdate ) IF li_coderet = -1 THEN invo_batchs.nvuf_ecriture_batchlog("Erreur le retrieve de la facture du controle agence") lb_retrieve_agnce = False ELSE lb_retrieve_agnce = True END IF lds_controle_client = CREATE datastore lds_controle_client.dataobject = 'd_t_factures_controle_client' lds_controle_client.SetTransObject( sqlca ) li_coderet = lds_controle_client.Retrieve( dt_sysdate ) IF li_coderet = -1 THEN invo_batchs.nvuf_ecriture_batchlog("Erreur le retrieve de la facture du controle client") lb_retrieve_clt = False ELSE lb_retrieve_clt = True END IF //****************************************************************** // Impression sur espace de la liste des factures client et agence //****************************************************************** IF lb_retrieve_agnce THEN invo_batchs.nvuf_save_fichier(ls_sauv_path,"fact_agence"+string(dt_sysdate,"ddmmyy")+".xls",lds_controle_agence) END IF IF lb_retrieve_clt THEN invo_batchs.nvuf_save_fichier(ls_sauv_path,"fact_client"+string(dt_sysdate,"ddmmyy")+".xls",lds_controle_client) END IF //****************************************************************** // Impression sur Fdupli de la liste des factures client et agence //****************************************************************** IF invo_impressions.nvuf_set_printer("Fdupli") = -1 THEN invo_batchs.nvuf_ecriture_batchlog("Erreur sur imprimante agence-duplication") ELSE IF lb_retrieve_agnce THEN li_coderet = lds_controle_agence.Print() IF li_coderet = -1 THEN invo_batchs.nvuf_ecriture_batchlog("Erreur d'impression de la liste des factures agence") END IF END IF IF lb_retrieve_clt THEN li_coderet = lds_controle_client.Print() IF li_coderet = -1 THEN invo_batchs.nvuf_ecriture_batchlog("Erreur d'impression de la liste des factures client") END IF END IF END IF invo_impressions.nvuf_restore_printer() DESTROY lds_controle_client DESTROY lds_controle_agence //**************************************************** // Creation de la datastore des factures à éditer //**************************************************** Ids_factures = CREATE datastore Ids_factures.dataobject = 'd_t_factures' Ids_factures.SetTransObject( sqlca ) // modifs du 22/05/06 (dc90) IF Ids_factures.Retrieve(dt_sysdate) = -1 THEN invo_batchs.nvuf_ecriture_batchlog("Erreur sur retrieve des factures à éditer : réessai dans 5 minutes") sleep (300) // attendre 5 minutes IF Ids_factures.Retrieve(dt_sysdate) = -1 THEN invo_batchs.nvuf_ecriture_batchlog("Nouvelle erreur sur retrieve des factures à éditer ") Close(this) END IF END IF datawindowchild ldwc_generalites //****************************************************************** // Recherche des factures à éditer sur imprimante 'agence' //****************************************************************** IF invo_impressions.nvuf_set_printer("Fagnce") = -1 THEN invo_batchs.nvuf_ecriture_batchlog("Erreur sur imprimante des agences") invo_impressions.nvuf_restore_printer() ELSE Ids_factures.SetFilter("cdecl_infcagcc = 'O' and fctcl_inimprfc = 'O' ") Ids_factures.Filter() Ids_factures.SetSort("cdecl_cdnumecc") // pour trier par agence Ids_factures.Sort() ll_rowcount = Ids_factures.RowCount() FOR ll_cptr = 1 TO ll_rowcount ls_idcodefc = Ids_factures.getitemstring(ll_cptr, 'fctcl_idcodefc') li_ind_facto = Ids_factures.getitemnumber(ll_cptr, 'ind_facto') dw_edition.DataObject = "d_c_edit_facture_bl_euro2" dw_edition.SetTransObject( sqlca ) // impression d'un ORIGINAL ib_fin_retrieve = FALSE ll_rep = dw_edition.Retrieve(ls_idcodefc, 'O', 'O', 'O', li_ind_facto) DO WHILE not ib_fin_retrieve LOOP IF ll_rep > 0 THEN // ajout ndu 20/03/06 : ne pas imprimer le mot DUPLICATA dw_edition.getchild ("generalites" , ldwc_generalites) ldwc_generalites.modify ("t_1.visible = 0 " ) invo_impressions.nvuf_set_printer("Fagnce") dw_edition.Print(False) invo_impressions.nvuf_restore_printer() //compteur du nombre de facture à imprimée ll_nbfc = ll_nbfc + 1 END IF NEXT invo_batchs.nvuf_ecriture_batchlog("fin d'impression des "+ string(ll_rowcount)+ " factures agence") END IF //****************************************************************** // Recherche des factures à éditer sur imprimante 'client' //****************************************************************** IF invo_impressions.nvuf_set_printer("Fclient") = -1 THEN invo_batchs.nvuf_ecriture_batchlog("Erreur sur imprimante des factures clients") invo_impressions.nvuf_restore_printer() ELSE Ids_factures.SetFilter("cdecl_infcagcc = 'N' and fctcl_inimprfc = 'O' ") Ids_factures.Filter() Ids_factures.SetSort("fctcl_idcodefc") Ids_factures.Sort() ll_rowcount = Ids_factures.RowCount() FOR ll_cptr = 1 TO ll_rowcount ls_idcodefc = Ids_factures.getitemstring(ll_cptr, 'fctcl_idcodefc') li_ind_facto = Ids_factures.getitemnumber(ll_cptr, 'ind_facto') dw_edition.DataObject = "d_c_edit_facture_bl_euro2" dw_edition.SetTransObject( sqlca ) // impression d'un ORIGINAL ib_fin_retrieve = FALSE ll_rep = dw_edition.Retrieve(ls_idcodefc, 'O', 'O', 'O', li_ind_facto) DO WHILE not ib_fin_retrieve LOOP IF ll_rep > 0 THEN // ajout ndu 20/03/06 : ne pas imprimer le mot DUPLICATA dw_edition.getchild ("generalites" , ldwc_generalites) ldwc_generalites.modify ("t_1.visible = 0 " ) invo_impressions.nvuf_set_printer("Fclient") dw_edition.Print(False) invo_impressions.nvuf_restore_printer() //compteur du nombre de factures à imprimer ll_nbfc = ll_nbfc + 1 END IF NEXT invo_batchs.nvuf_ecriture_batchlog("fin d'impression des "+ string(ll_rowcount)+ " factures clients") END IF // pour ne pas recuperer tous les jours dans d_t_factures les factures avec fctcl_inimprfc = 'N' Ids_factures.SetFilter("") Ids_factures.Filter() ll_rowcount = Ids_factures.RowCount() FOR ll_cptr = 1 TO ll_rowcount ls_idcodefc = Ids_factures.GetItemString(ll_cptr , "fctcl_idcodefc") UPDATE fctcl SET ineditfc = 'O' WHERE idcodefc = :ls_idcodefc; IF sqlca.sqlcode <> 0 THEN li_error = sqlca.sqldbcode ROLLBACK USING sqlca; invo_batchs.nvuf_ecriture_batchlog("Erreur SQL : " +& string(li_error) + " lors de la maj de la facture " + ls_idcodefc) ELSE COMMIT USING sqlca; END IF NEXT //****************************************************************** // Fin du batch d'édition des factures //****************************************************************** IF ll_nbfc = 0 THEN invo_batchs.nvuf_ecriture_batchlog("Il n'y a aucune facture à éditer") ELSE invo_batchs.nvuf_ecriture_batchlog(string(ll_nbfc) + " factures ont été éditées") END IF // si des factures contiennent que des frais de port standard à 0 et indicateur //d'impression à Non sur lgncl Ids_factures.SetFilter( " fctcl_inimprfc = 'N' ") Ids_factures.Filter() ll_nbfc_non_imp = Ids_factures.RowCount() IF ll_nbfc_non_imp > 0 THEN invo_batchs.nvuf_ecriture_batchlog(string(ll_nbfc_non_imp) + " factures n'ont pas été éditées à cause de l'indicateur à Non ") END IF Close(this)
Une petite idée ??
Hors ligne
datastore lds_controle_client , lds_controle_agence
ces deux datastores sont encore locales... peut-être que :
pick ouic a écrit:
mets la en variable d'instance
tu la crées à l'open de la fenetre
et tu la detruis à l'évenement Close de la fenetre...
cela dit j'utilise généralement les datastores en local et ça ne pose pas de problème... à voir
Hors ligne
mais le destroy sur ces 2 datastores ne pose pas de problème. et l'autre datastore était en local avant.
Mais effectivement, nous avons de nombreuses datastore en local qui ne posent aucun problème.
Mystère, mystère.
Hors ligne
passes les tous en variables d'instances...
et tu fais la meme chose que pour l'autre datastore...
je me demande s'il y a pas un lien aussi avec le timing... le fait que ca aille trop vite peut etre ?
Hors ligne
c'est quoi qui va trop vite, le destroy ?? , je peux mettre une pause juste avant sinon....
Hors ligne
essayes de mettre un timer entre chaque requete... et avant le destroy...si tu laisses tout ca en locale...
Hors ligne
Tu parles de la fonction timer ??? ou sleep ????
Sleep je sais bien ce que ça fait , timer j'ai jamais utilisé....
Hors ligne
moi, un truc m'étonnes,
tu fais dans le script un close, sans faire de return ...
... ... Ids_factures = CREATE datastore Ids_factures.dataobject = 'd_t_factures' Ids_factures.SetTransObject( sqlca ) // modifs du 22/05/06 (dc90) IF Ids_factures.Retrieve(dt_sysdate) = -1 THEN invo_batchs.nvuf_ecriture_batchlog("Erreur sur retrieve des factures à éditer : réessai dans 5 minutes") sleep (300) // attendre 5 minutes IF Ids_factures.Retrieve(dt_sysdate) = -1 THEN invo_batchs.nvuf_ecriture_batchlog("Nouvelle erreur sur retrieve des factures à éditer ") Close(this) END IF END IF ... ...
est-ce qu'il ne faudrait pas rajouter un return par hasard ???
Hors ligne
et sinon c'est vraiment absolument necessaire de faire un destroy ?
Y a un garbage collector dans PB qui devrait s'en charger tout seul à terme et qui le fera peut etre sans problemes.
Hors ligne
il me semble qu'il y a des soucis avec le garbage collector et les datastore, je crois qu'il gère mal et les laisse en mémoire :x
Hors ligne
Bonjour,
Voici les infos du jour après une nouvelle execution du batch cette nuit.
J'ai laissé la datastore en instance et j'ai ajouté la commande sleep avant le destroy.
Mauvaise nouvelle, le Sleep n'arrange pas mes problèmes. J'ai mis un Sleep(120), pour faire une pause de 2 minutes, mais le résultat est identique, le destroy plante lamentablement.
Quand au close, il est présent dans la fenêtre afin de fermer la fenetre si le retrieve ne se passe pas correctement, l'execution du batch ne passe donc que très rarement par là.
Et si on ne fait pas le destoy manuellement, lorsque le batch se termine, il fait également Docteur Watson donc la même erreur que lors du destroy en manuel.
Hors ligne
oui, mais apres un close, il faut toujours mettre un Return...surtout quand il y a des scripts apres...
tu l'as placé ou les Sleep ?
Hors ligne
ha désolée pour le close, je vais ajouté le return.
voici ou j'ai mis le sleep
If IsValid(Ids_factures) then
Sleep (120)
DESTROY Ids_factures
invo_batchs.nvuf_ecriture_batchlog("Destroy de lds_facture effectué.")
end if
Hors ligne
t'as mis des sleeps sur les autres destroy ?
Hors ligne
ben non, j'en ai ajouté uniquement un a cet endroit.
Hors ligne
avant de faire le destroy, essaie de faire un dw.reset()
Hors ligne