Artículo
· 4 hr atrás Lectura de 2 min

Archivos temporales y Singletons: limpiad lo que generéis.

Hay un patrón con el que me he encontrado varias veces en el que necesito usar un archivo o carpeta temporal y que se limpie en algún momento más adelante.

Lo natural aquí es seguir los patrones de "Robust Error Handling and Cleanup in ObjectScript" usando un try/catch/pseudo-finally o un objeto registrado para gestionar la limpieza en el destructor. %Stream.File* también tiene una propiedad “RemoveOnClose” que podéis activar… pero usadla con cuidado, porque podríais eliminar accidentalmente un archivo importante, y este indicador se reinicia al llamar a %Save(), así que tendréis que volver a ponerlo a 1 después de hacerlo.

Pero hay un caso complicado: imaginad que necesitáis que el archivo temporal sobreviva en un nivel de pila superior. Por ejemplo:

ClassMethod MethodA()
{
    Do ..MethodB(.filename)
    // Do something else with the filename
}

ClassMethod MethodB(Output filename)
{
    // Create a temp file and set filename to the file's name
    Set filename = ##class(%Library.File).TempFilename()
    
    //... and probably do some other stuff
}

Siempre podríais pasar objetos %Stream.File* con RemoveOnClose puesto a 1, pero aquí realmente estamos hablando solo de archivos temporales.

Aquí es donde entra el concepto de “Singleton”. En IPM tenemos una implementación base en %IPM.General.Singleton que podéis extender para cubrir distintos casos de uso. El comportamiento general y el patrón de uso son:

  • En un nivel de pila superior, llamáis a %Get() en esa clase y obtenéis la única instancia, que también será accesible mediante llamadas a %Get() en niveles inferiores.
  • Cuando el objeto sale de ámbito en el nivel de pila más alto que lo usa, se ejecuta el código de limpieza.

Esto es un poco mejor que usar una variable %, porque no necesitáis comprobar si está definida, y además sobrevive a los NEW sin argumentos en los niveles de pila inferiores gracias a cierta magia profunda de objetos.

Pasando a los archivos temporales, IPM también tiene un singleton gestor de archivos temporales. Aplicándolo a este problema, la solución es:

ClassMethod MethodA()
{
    Set tempFileManager = ##class(%IPM.Utils.TempFileManager).%Get()
    Do ..MethodB(.filename)
    // Do something else with the filename
    // The temp file is cleaned up automatically when tempFileManager goes out of scope
}

ClassMethod MethodB(Output filename)
{
    Set tempFileManager = ##class(%IPM.Utils.TempFileManager).%Get()
    // Create a temp file and set filename to the file's name
    Set filename = tempFileManager.GetTempFileName(".md")
    
    //... and probably do some other stuff
}
Comentarios (0)1
Inicie sesión o regístrese para continuar