I have a package that lets a user log into another system and I want it to be sure to log the user out, at least by the time the R session is over.
My Login(username,password) function stashes a token (the username in my simplfied code) in an environment and my Logout() function needs to use that stored token to logout. Logout() sets the stored token to NULL when it is done and the stored token is NULL when the package is loaded. I first tried calling the logout function from a finalizer registered in .onLoad. This basicly worked: > testFinalize::Login("Bill") [Loading testFinalize from /homes/bill/packages/tmp/lib] *** Logging in user Bill *** > q("no") [invoking registered finalizer] *** Logging out user Bill *** However, it failed when the user manually unloaded the package's namespace. In that case, running the registered finalizer, either because the session ended or because of a garbage collection, caused the namespace to be reloaded, so the stored token is NULL, making it look like no logout is required: > testFinalize::Login("Bill") [Loading testFinalize from /homes/bill/packages/tmp/lib] *** Logging in user Bill *** > unloadNamespace("testFinalize") [Unloading /homes/bill/packages/tmp/lib/testFinalize] --- Not calling Logout at unload time --- > gc() # or q() [invoking registered finalizer] [Loading testFinalize from /homes/bill/packages/tmp/lib] *** No need to log out *** used (Mb) gc trigger (Mb) max used (Mb) Ncells 255820 13.7 460000 24.6 350000 18.7 Vcells 535039 4.1 1023718 7.9 786426 6.0 If I only call Logout() from .onUnload, and not from the registered finalizer, nothing happens when the R session is done, since packages are not unloaded then. It looks like I need to call Logout from both .onUnload and from the registered finalizer to make sure it gets called. Is that right or is there a standard way to make sure some package-specific cleanup gets done? Since the finalizer will still cause the package's namespace to be loaded we waste some time after q(). Is there a way to unregister a finalizer so we can avoid the reloading? I've appended the R code in the package below. The package exports Login, Logout, and LogoutAtUnload. The last lets you force .unLoad to call Logout() or not. Reply privately if you want the tar.gz file for the test package. Bill Dunlap TIBCO Software wdunlap tibco.com .loginInfo <- list2env( list(token = NULL, logoutAtUnload = FALSE) ) Login <- function(username, password) { if (is.null(.loginInfo$token)) { message("*** Logging in user ", username, " ***") .loginInfo$token <- username } else { message("*** Cannot log in user ", username, ", ", .loginInfo$token, " is already logged in ***") } } Logout <- function() { if (!is.null(.loginInfo$token)) { message("*** Logging out user ", .loginInfo$token, " ***") .loginInfo$token <- NULL } else { message("*** No need to log out ***") } } LogoutAtUnload <- function(flag = NA) { stopifnot(is.logical(flag), length(flag)==1) old <- isTRUE(.loginInfo$LogoutAtUnload) if (!is.na(flag)) { .loginInfo$LogoutAtUnload <- flag } old } .onLoad <- function(libname, pkgname) { message("[Loading ", pkgname, " from ", libname, "]") reg.finalizer(getNamespace(pkgname), function(envir) { message("[invoking registered finalizer]"); Logout()}, onexit=TRUE) } .onUnload <- function(libpath) { message("[Unloading ", libpath, "]") if (LogoutAtUnload()) { Logout() } else { message("--- Not calling Logout at unload time ---") } } [[alternative HTML version deleted]] ______________________________________________ R-package-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-package-devel