martedì 24 gennaio 2017

Gestione Semaforo

Accade a volte che la gestione dello stesso file può avvenire da programmi differenti o comunque da postazioni/utenti differenti.

In questi casi è utile la gestione di un semaforo per far lavorare i programmi uno alla volta: se trovo il semaforo rosso attendo il mio turno appena diventa verde.

Per esempio noi gestiamo la stampa delle etichette tramite l'applicazione NICELABEL: tutte le informazioni vengono scritte in un file, ma lo stesso file può essere scritto da programmi o utenti differenti; è importante gestire il fatto che non ci siano sovrapposizioni che porterebbero ad errori o inconsistenze.

La cosa più semplice è gestire il semaforo come l'esistenza di un file:

   se il file esiste -> semaforo rosso
   se il file non esiste -> semaforo verde

Uno dei pericoli in questi casi è che, per un errore o comunque una anomalia, un semaforo resti rosso (per qualche motivo non è stato cancellato il file) e tutte le elaborazioni successive risultano bloccate.

Una soluzione è quella di scrivere, all'interno del file, data e ora di creazione e un TTL (Time To Live), cioè il tempo di vita del semaforo: se il semaforo è rosso controllo quanto tempo è passato dalla creazione, se è superiore al TTL allora procedo come se il semaforo fosse verde.

Per tutta questa gestione ho costruito un Function Module SAP al quale viene passato:

   Nome del file semaforo
   operazione da eseguire (OPEN, CLOSE)
   num.secondi attesa (default 2)
   Numero di volte che provo ad accendere (default 5)
   TTL

Nome FM Z_SEMAFORO

FUNCTION Z_SEMAFORO.
*"----------------------------------------------------------------------
*"*"Interfaccia locale:
*"  IMPORTING
*"     REFERENCE(FILE_NAME) TYPE  FILE_NAME
*"     REFERENCE(OPERAZIONE) TYPE  CHAR05
*"     REFERENCE(WAIT_SEC) TYPE  INT2 OPTIONAL
*"     REFERENCE(NUM_CICLI) TYPE  INT2 OPTIONAL
*"     REFERENCE(TTL) TYPE  INT4 OPTIONAL
*"  EXPORTING
*"     REFERENCE(ESITO) TYPE  CHAR02
*"     REFERENCE(MESSAGGIO) TYPE  CHAR200
*"----------------------------------------------------------------------
* Autore     : Fabio Giacobbe - 02/12/2016                             |
* Descrizione: Gestione di un file semaforo.                           |
*----------------------------------------------------------------------+
* Modifiche  :            by                                           |
* Note       :                                                         |
*----------------------------------------------------------------------+
* parametri
*   ingresso:
*      FILE_NAME : Nome del file semaforo
*      OPERAZIONE: operazione da eseguire
*                     - OPEN : accendi semaforo
*                     - CLOSE: spegni semaforo
*      WAIT_SEC  : num.secondi attesa (default 2)
*      NUM_CICLI : Numero di volte che provo ad accendere (default 5)
*      TTL       : Nel file semaforo viene scritto:
*                     - data
*                     - ora
*                     - vita max in secondi
*                  Se il semaforo è acceso si controlla se la vita
*                  massima è già superata, nel caso si sovrascrive.
*
*   uscita:
*      ESITO     : OK = operazione eseguita
*                  KO = operazione fallita
*      MESSAGGIO : messaggio di errore
*----------------------------------------------------------------------+
* Descrizione funzionamento: lavora in base all'operazione da eseguire:
*
*   OPEN: Si tenta di aprire il file passato in ingresso se:
*            - il file non esiste: si scrive un nuovo file.
*            - il file esiste: si legge la prima riga e si calcola da
*              quanti secondi è stato creato. Quindi si verifica se il
*              TTL (Time to live) è stato superato:
*                 - se è già stato superato si sovrascrive il file con
*                   i nuovi valori.
*                 - se invece non è stato superato si attende i secondi
*                   passati in ingresso e poi si tenta nuovamente (per
*                   il numero di volte passato in ingresso)
*
*   CLOSE: Si cancella il file passato in ingresso.
*----------------------------------------------------------------------+
* Nota: Assicurarsi che gli utenti di servizio SAPservice<SID> abbiano
*       accesso completo al percorso file.
*----------------------------------------------------------------------+

   CASE operazione.
    WHEN 'CLOSE'.
      PERFORM spegni-semaforo USING file_name
                                    esito
                                    messaggio.
    WHEN 'OPEN'.
    WHEN OTHERS.
      messaggio = text-001.
   ENDCASE.

   CHECK operazione = 'OPEN'.

   data: wa_wait_sec  type INT2,
         wa_num_cicli type INT2,
         wa_ttl       type INT4,
         wa_secondi   type INT4,
         wa_ttl_file  type INT4.

   Data: BEGIN OF record,
           sysdate like sy-datum,
           systime like sy-uzeit,
           ttl(10),
         end of record.

   IF WAIT_SEC IS INITIAL.
      wa_wait_sec = 2.
   else.
      wa_wait_sec = WAIT_SEC.
   ENDIF.

   IF NUM_CICLI IS INITIAL.
      wa_num_cicli = 5.
   else.
      wa_num_cicli = NUM_CICLI.
   ENDIF.

   IF ttl IS INITIAL.
      wa_ttl = wa_wait_sec * wa_num_cicli.
   else.
      wa_ttl = ttl.
   ENDIF.

   DO wa_num_cicli TIMES.

* verifico se il file esiste.
      OPEN DATASET file_name FOR INPUT IN TEXT MODE ENCODING DEFAULT.
      if sy-subrc <> 0.
         PERFORM accendi-semaforo using file_name
                                        wa_ttl
                                        esito
                                        messaggio.
         EXIT.
      endif.

* Il file esiste, leggo il contenuto e verifico se è superato il TTL
      READ DATASET file_name into record.
      CLOSE DATASET file_name.

      wa_ttl_file = record-ttl.

      CLEAR wa_secondi.
* calcolo la differenza in secondi tra data attuale e data file
      CALL FUNCTION 'SALP_SM_CALC_TIME_DIFFERENCE'
        EXPORTING
          date_1        = sy-datum
          time_1        = sy-uzeit
          date_2        = record-sysdate
          time_2        = record-systime
        IMPORTING
          SECONDS       = wa_secondi
                .
      if wa_ttl_file < wa_secondi.
* il precedente file semaforo è già scaduto, pertanto scrivo nuovo file
         PERFORM accendi-semaforo using file_name
                                        wa_ttl
                                        esito
                                        messaggio.
         EXIT.
      endif.

      WAIT UP TO wa_wait_sec SECONDS.

   ENDDO.

ENDFUNCTION.

*&---------------------------------------------------------------------*
*&      Form  spegni semaforo
*&---------------------------------------------------------------------*
form spegni-semaforo USING file_name
                           esito
                           messaggio.

   DELETE DATASET file_name.
   IF sy-subrc = 0.
      esito = 'OK'.
   else.
      esito = 'KO'.
   ENDIF.

endform.                    " spegni-semaforo
*&---------------------------------------------------------------------*
*&      Form  accendi semaforo
*&---------------------------------------------------------------------*
form accendi-semaforo USING file_name
                            wa_ttl
                            esito
                            messaggio.

   Data: BEGIN OF record,
           sysdate like sy-datum,
           systime like sy-uzeit,
           ttl(10),
         end of record.

   record-sysdate = sy-datum.
   record-systime = sy-uzeit.
   write wa_ttl to record-ttl.
   OPEN DATASET file_name FOR OUTPUT IN TEXT MODE ENCODING DEFAULT.
   if sy-subrc <> 0.
      esito = 'KO'.
      messaggio = text-002.
   else.
      TRANSFER record TO file_name.
      CLOSE DATASET file_name.
      esito = 'OK'.
   endif.

endform.                    " accendi-semaforo

Definizione testi:

text-001 Operazione semaforo non corretta!
text-002 Impossibile creare file semaforo

Parametri importazione:

Parametri esportazione:

esempio di chiamata alla funzione

  CALL FUNCTION 'Z_SEMAFORO'
     EXPORTING
        file_name        wa_file_name
        operazione       'OPEN'
        wait_sec         5
        num_cicli        10
        ttl              60
*    IMPORTING
*       ESITO            = wa_esito
*       MESSAGGIO        = wa_messaggio
     .

Nessun commento:

Posta un commento