How does R handle closing of data base connections - r

If I create a data base connection within a function, the connection objects gets destroyed when the function finished executing. Does this reliably close the data base connection, or would it better to to close it manually first?
Why I need to know this:
I am working on a package that creates data base connections on the fly with either RODBC or RJDBC as backend. I designed my function interfaces so that you can pass in either username and password, or a connection object. Usually, when I pass in a connection object I do not want the connection to be closed on the termination of the function, while when I pass in username and password I want it to be closed.
If I do not have to worry about open connections, it would simplify things a lot for me and also save me a lot of headaches.
Answer & More:
I markded Benjamin's answer as the answer since it gives good advice, though actually what I was looking for is more Marek's comment that (paraphrased:) connections can be open after the connection object is destroyed and there is no way to access them from R any more.
I ended up going for a solution that involves creating an R6 class and defining finalize() method that closes the connection (it's a more powerful than on.exit()), but that is beyond the scope of this Question.

I write a lot of functions that create ODBC connections when they are called. My standard practice is:
conn <- RODBC::odbcDriverConnect(...)
on.exit(RODBC::odbcClose(conn))
By putting the creation of the object and the code for its closing next to each other, I know that the connection will be closed when the function is finished. Using on.exit has the added advantage of closing the connection even if the function stops on an error.
Edit:
In the problem as your edit has described it, I think the same pattern is relevant. You need to declare on.exit in a manner that it only gets called if you don't provide the connection object.
db_function <- function(conn = NULL, uid, pwd){
if (is.null(conn)){
conn <- RODBC::odbcDriverConnect(...) # Build conn with uid and pwd
on.exit(RODBC::odbcClose(conn))
}
}
A trivial example to show by-passing on.exit
test_fun <- function(on_exit = FALSE){
if (on_exit) on.exit(print("hello world"))
"Look at me"
}
test_fun()
test_fun(TRUE)

Related

In R, how to check if an object exists in memory from inside the object itself?

I've been running into this problem in a few separate cases now and I'd like your input. In R, objects can be deleted or overwritten, but if they use Rcpp libraries, they will keep doing what they do.
For example, when connecting to a websocket using the websocket package:
ws<-WebSocket$new(paste0(gate,"/?v=6&encoding=json"),autoConnect=F)
ws$onMessage(function(event) {
print(event)
})
ws$connect()
The object ws is now my only way to control the websocket, and if it is deleted or overwritten, there is no way to make it disconnect except to restart R.
A similar issue when using the later package:
BumpUp<-function(.self){
.self$iter<-.self$iter+1
message("Valued bumped up to ",.self$iter)
if(.self$iter<10){
later::later(~.self$bump(),delay=1)
}
}
MakeTestObject<-setRefClass("testobject",fields=list(iter="numeric"),methods=list(bump=BumpUp))
testobj<-MakeTestObject(iter=0)
testobj$bump()
rm(testobj)
the loop associated with testobj continues to repeat, despite the fact that the object itself has been removed from memory.
Is there any way to make a reference class object check if it still exists in memory? More generally, is it possible for the object to know its name in memory?

How do you get code to execute at the end of a procedure?

I'm working on a new piece of code at work to assist the rest of the programmers in making app server calls. Previously we just had a .i file and relied on the developer to make sure you made all the right calls and cleaned up the app server connection at the end of the program. Obviously some people have forgotten to do that in the past and it's caused problems for us.
I've been building a basic appserver.cls file, but I can't figure out how to get it to disconnect at the end of the program.
I've tried the following things so far.
ON CLOSE OF THIS-PROCEDURE
DO:
clAppServer:cleanupAppServer().
END.
This doesn't seem to fire at the end of the webspeed call.
DESTRUCTOR appserver():
cleanupAppServer().
END DESTRUCTOR.
This works when it does garbage collection, but Progress doesn't seem to do garbage collection at the end of a webspeed call and the objects are still in memory (which is an entirely different issue that I need to deal with).
ON CLOSE OF SESSION:LAST-PROCEDURE
DO:
clAppServer:cleanupAppServer().
END.
This doesn't even compile obviously.
I've tried a whole bunch of other things that are variants on these three to no avail.
Is there any way to do what I'm asking? Bonus points if it can be inside the appserver.cls file.
If I understand the question, you want to disconnect from another AppServer once the work is done. Would try something along the lines of the below work?
Create a AppServer-handle-wrapper class. This class is responsible for the A/S connection; it has a public "Handle" (or similarly-named) property that you can use to run stuff on the AppServer.
In this class' destructor you can add code that does your clean-up : disconnect and delete server handle .
Code that wants to run something on the AppServer does something like ...
def var asConn as AppServerConnection.
asConn = new AppServerConnection().
run foo.p on asConn:Handle (param1, out param2).
// cause GC
asConn = ?.
// manually destroy
delete object asConn.
The destructor will then do the right thing.
Note that if you have this code in an internal procedure or method, then the variable would go out of scope at the end of it, and the GC would kick in.
There's an example of this approach at https://github.com/consultingwerk/ADE-Sourcecode/blob/566ac0a6e085d6305a8f364f13a1d805d3597d2a/src/netlib/OpenEdge/Net/ServerConnection/ClientSocket.cls
Bear in mind that in the ClientSocket is that the handle is private - you may want to make it public for a general AppServer connection.

mongolite best practices

I am developing an application using OpenCPU and R, I am totally new to both. I am using mongolite package to connect to MongoDB. There are multiple calls to the DB and connecting every time, takes really long. Plus data processing, plotting etc. takes quite a lot of time to load the page with the generated plot. In many cases, I have to plot fetching data from multiple collections.
I noticed that i am able to save 3-4 seconds (per connection) if I don't connect to DB each and every time, rather use an existing connection.
Will be great if anyone can guide me with the best way to check if connection is already established to the DB.
Let me brief you on what I have done so far!
Here is my connect_to_db.R file
library(mongolite)
dbConnection <- NULL
connect_mongodb = function() {
db={
if(is.null(dbConnection)){ # connect to DB only if connection is NULL, else return global connection object
m <- mongo(collection = myCollection, db = myDb, url = myUrl)
assign("dbConnection", m, envir = .GlobalEnv)
}
return(dbConnection)
}
}
It serves the purpose on sourcing the file and running it from R console. But, when I use it in my opencpu server, I make a call to connect_mongodb method from another R method that I use for plotting. I call the plotting method from a javascript file as follows.
var req = $("#plot").rplot(myPlottingMethod, options).fail(function(){
alert("Error loading results");
})
This way, my variable "dbConnection" is unknown to the method.
I tried few other ways of using <<- which i read isn't a good way to do it. Also I tried using exists() in place of is_null.
I tried another option of calling my connect_mongodb method from my javascript file using ocpu.rpc call with an idea of passing it as an argument to the R methods in rplot calls.
var req = ocpu.rpc("connect_mongodb", {})
Since connecting to mongolite doesnt return a JSON object, this attempt also failed with the below error
Failed to get JSON response for http://localhost:xxxx/ocpu/tmp/x07c82b16bb/
sadly, toJSON of jsonlite and rjson did not help in converting the db object to JSON

Pyodbc - Web.py blocking connection

I am currently using PYODBC in Web.py to connect to a SQL Azure DB and so far all was well. We recently added a new call into our Web.py URL list which made a cursor call like follows
class get_teas:
def GET(self):
con = pyodbc.connect(con_string,timeout=120)
con.timeout = 120
cur = con.cursor()
for row in cur.execute("{CALL get_all_tea_in_china ("+user_data.theother+",'"+user_data.this+"','"+user_data.that+"')}"):
...do some dictionary stuff
cur.commit();
cur.close()
return 'DONE'
However we have recently noticed due to get_all_tea_in_china being a long call that it is blocking all subsequent calls within web.py which is not great for hopefully obvious reasons! Is there a way of making it such that this call is not blocking?
If anyone can help I would really appreciate it.
You can use celery,put your long call in a asynchronous task queue.http://www.celeryproject.org/

Asp.Net MVC double submit/request breaks SQL connection

I am running into a strange problem I don't fully understand. The main symptom is that when I double click a link (that points to a controller action) in my MVC application, my database server connection gets blown, and I get the error :
Execution of the command requires an open and available connection. The connection's current state is broken.
If I step through starting at a breakpoint at the top of the controller action, it will step down a couple lines and then jump back up to the breakpoint. Somehow the first request isn't executing fully before the second one gets there, and somehow my database connection breaks when it gets to any query. Every time this happens, I have to restart the application server.
It was happening intermittently at first, but the double clicking of links seems to reproduce it everytime. Does this happen to anyone else? What am I missing here?
Thanks,
rusty
Update :
A.) I incorrectly tagged this as Linq-to-sql when we are actually using Linq-to-entities.
B.) The connection object is defined as a member variable of the controller :
namespace C2S.Controllers
{
public class ArtifactController : Controller
{
private c2sEntities _entities = new c2sEntities();
...
I noticed in some of the asp.net tutorials they declare the variable in the same spot but have a separate constructor for the controller where the db object is initialized. Does this make any difference?
C.) The problem is not only with the double-clicking as described above. The connection breaks at other seemingly random times; I cannot seem to reproduce the error consistently (even double-clicking does not always break it). Restarting the web site usually fixes it, although sometimes I have to restart the host machine. After its back up, repeating the same sequence of actions usually does not reproduce the same error!
Maybe there's something I don't understand about setting up my linq-to-entities classes or the nature of the database connection. Does anyone have any thoughts? I really don't even know how to investigate this one!
Thanks again
Rusty
It's a bit difficult to say from your description of the problem, but a first guess would be:
Is your connection object static (i.e. controller or application level) or defined locally within the action? Double clicking a link would fire the event twice and that sounds like what you are describing here. So the first call creates the connection, then the 2nd call comes in and tramps all over the 1st call to the method, breaking the connection it thinks it has.
Edit: Does the problem only occur on double clicks. Does it work as expected if you only single click on the link? An example of the code in question would help.
I am guessing that you're not properly closing your database connection. You should consider making use of the using statement.
using(SqlConnection conn = new SqlConnection("connstring")) {
using (SqlCommand cmd = new SqlCommand("SQLSTATEMENT", conn)) {
// more code here......
}
}
This will ensure that your connection is closed even if there's an error in your code somewhere.
Read all about it here: http://davidhayden.com/blog/dave/archive/2005/01/13/773.aspx

Resources