Asynchronous calls to sql server 2000

D

dkil1972

In upgrading an application to .Net 2.0 from 1.1 I had an opportunity
to implement some asynchronous calls to the database. In the
application there is a quick search facility that makes 6 calls to 3
different database. This I thought was the perfect scenario for
Asynchronous calls.

Anyway i implemented it and tested it in our win2003 testing
environment calling to a sqlserver instance on the same machine. The
testing worked and I went live with the application. I did not stress
test the application (although i found a nifty stress testing
application which you can get here http://www.opensta.org/).

The live environment is also win2003, with the sqlserver instance on a
seperate machine. Soon after deploying to live we started getting the
following error.

The timeout period elapsed prior to obtaining a connection from the
pool. This may have occurred because all pooled connections were in
use and max pool size was reached.

I did some investigating using the stress testing application, which
was set to invoke 100 requests with a 1 second interval on the test
server. Then using Management Studio Activity monitor i checked the
connection activity. Immediately after starting the requests the
number of connections started to rise, in the end it went from 25 upto
180. It took a full minute for that number to start dropping.

I then used Sql Profiler and saw that for each request a new set of 6
connections was being created but these connections are neither reused
nor closed.
Anyway here is the code...

Here i am registering the async task with the page containing the
user control

SearchDataMgr mgr = new SearchDataMgr(_criteria);
Page.RegisterAsyncTask(mgr.GetEmcProductData(product));

Page.RegisterAsyncTask(mgr.GetEmcCompanyData(company));

Page.RegisterAsyncTask(mgr.GetXpilData(dgXpil));

Page.RegisterAsyncTask(mgr.GetPCDDAmpData(amp));

Page.RegisterAsyncTask(mgr.GetPCDDVmpData(vmp));

Page.RegisterAsyncTask(mgr.GetPcddSupplierData(supplier));

All of the getter method calls used as parameters are implemented in
the same way. here is the first one...

public PageAsyncTask GetEmcProductData(BaseDataList
controlToBindTo)
{
string connectionString =
ConfigurationManager.AppSettings["connectionString"].ToString() +
";async=true";
_conn = new SqlConnection(connectionString);

_emcComm = new SqlCommand();
_emcComm.CommandText = ("usp_SearchProduct");
_emcComm.Parameters.AddWithValue("@criteria", _criteria);
_emcComm.CommandType = CommandType.StoredProcedure;
_emcComm.Connection = _conn;
_conn.Open();
AsyncState state = new AsyncState(_emcComm,
controlToBindTo, "command");
PortalSearchDataAsyncHandler productHandler = new
PortalSearchDataAsyncHandler();
return new PageAsyncTask(
new
BeginEventHandler(productHandler.BeginGetSearchData),
new
EndEventHandler(productHandler.EndGetSearchData),
new
EndEventHandler(productHandler.GetSearchDataTimeout),
state, true);

}//end method

I have a data PortalSearchDataAsyncHandler object that contains the
three handler methods required by the PageAsyncTask object. Here is
the code for the async handler methods...

internal IAsyncResult BeginGetSearchData(object src, EventArgs
e, AsyncCallback cb, object state)
{
AsyncState command = state as AsyncState;
return command.Command.BeginExecuteReader(cb, state);
}

internal void EndGetSearchData(IAsyncResult ar)
{

AsyncState commState = ar.AsyncState as AsyncState;

DataTable resultsTable = new DataTable();

SqlDataReader resultsReader =
commState.Command.EndExecuteReader(ar);
try
{
using (resultsReader)
{
resultsTable.Load(resultsReader);
commState.ControlToBindTo.DataSource =
resultsTable;
commState.ControlToBindTo.DataBind();
}
}
finally
{
commState.Command.Connection.Close();
}
}

internal void GetSearchDataTimeout(IAsyncResult ar)
{
AsyncState commState = ar.AsyncState as AsyncState;
// operation timed out, so just clean up by closing the
connection
if (commState.Command.Connection.State ==
ConnectionState.Open)
commState.Command.Connection.Close();
//_messageLabel.Text = "Query timed out...";
}

Anyway I have had to go back to doing all of this synchronously as I
can't believe that the synchronous calls are more efficient in this
case.

Thanks in advance for any help or suggestions,

Cheers

Dermot
 
W

William \(Bill\) Vaughn

Okay, on brief inspection I don't see anything egregious here, but consider that the async op is only 1/2 (or less) of the operation. Does it make the application faster? Sure it can when applications are held back by operations that can be done in parallel--as it looks like in your case. However, the data fetch is still synchronous.

The exception you're getting is (generally) caused by one of two things:
1.. The code is not closing the connection and releasing it back to the connection pool. This is not that common any more as most developers have picked up on this issue, but it can creep in if you don't make sure that the connection is released when an exception is fired. Another typical cause of this issue is when passing a DataReader that's not opened with CommandBehavior.CloseConnection. You aren't doing this but I expect you should.
2.. The server is overloaded. That is when the server is asked to perform an operation, it holds the connection until the results are (all) returned. Remember this portion of the operation is synchronous. If another operation comes in before the first is done (as often happens) ADO.NET must create another clone of the connection and put it in the pool. This additional load can slow down the server even more. If this second operation causes the first to block (poor design), you have other issues... If the server never catches up, the pool continues to grow until you reach 100 connections (the default upper limit).
Typically, a heavily used system consumes about 25 connections. With a faster processor(s), more RAM and good design it might make the number lower or higher (capable of keeping the pool small because it's more efficient or capable of handling more operations per second).

Async ops can buy you some cycles if they were wasted on serializing operations.
Warning: Be sure you don't have MARS enabled--not unless you're absolutely sure you know all of the issues involved.

I'll be discussing this very issue tonight at the Greater New Orleans ..NET User Group. I'll be at the Dallas .NET UG the 24th, the Aggieland UG the afternoon of the 25th and San Antonio the 26th. This is also discussed in great depth in my book.

--
____________________________________
William (Bill) Vaughn
Author, Mentor, Consultant
Microsoft MVP
INETA Speaker
www.betav.com/blog/billva
www.betav.com
Please reply only to the newsgroup so that others can benefit.
This posting is provided "AS IS" with no warranties, and confers no rights.
__________________________________
Visit www.hitchhikerguides.net to get more information on my latest book:
Hitchhiker's Guide to Visual Studio and SQL Server (7th Edition)
and Hitchhiker's Guide to SQL Server 2005 Compact Edition (EBook)
-----------------------------------------------------------------------------------------------------------------------

dkil1972 said:
In upgrading an application to .Net 2.0 from 1.1 I had an opportunity
to implement some asynchronous calls to the database. In the
application there is a quick search facility that makes 6 calls to 3
different database. This I thought was the perfect scenario for
Asynchronous calls.

Anyway i implemented it and tested it in our win2003 testing
environment calling to a sqlserver instance on the same machine. The
testing worked and I went live with the application. I did not stress
test the application (although i found a nifty stress testing
application which you can get here http://www.opensta.org/).

The live environment is also win2003, with the sqlserver instance on a
seperate machine. Soon after deploying to live we started getting the
following error.

The timeout period elapsed prior to obtaining a connection from the
pool. This may have occurred because all pooled connections were in
use and max pool size was reached.

I did some investigating using the stress testing application, which
was set to invoke 100 requests with a 1 second interval on the test
server. Then using Management Studio Activity monitor i checked the
connection activity. Immediately after starting the requests the
number of connections started to rise, in the end it went from 25 upto
180. It took a full minute for that number to start dropping.

I then used Sql Profiler and saw that for each request a new set of 6
connections was being created but these connections are neither reused
nor closed.
Anyway here is the code...

Here i am registering the async task with the page containing the
user control

SearchDataMgr mgr = new SearchDataMgr(_criteria);
Page.RegisterAsyncTask(mgr.GetEmcProductData(product));

Page.RegisterAsyncTask(mgr.GetEmcCompanyData(company));

Page.RegisterAsyncTask(mgr.GetXpilData(dgXpil));

Page.RegisterAsyncTask(mgr.GetPCDDAmpData(amp));

Page.RegisterAsyncTask(mgr.GetPCDDVmpData(vmp));

Page.RegisterAsyncTask(mgr.GetPcddSupplierData(supplier));

All of the getter method calls used as parameters are implemented in
the same way. here is the first one...

public PageAsyncTask GetEmcProductData(BaseDataList
controlToBindTo)
{
string connectionString =
ConfigurationManager.AppSettings["connectionString"].ToString() +
";async=true";
_conn = new SqlConnection(connectionString);

_emcComm = new SqlCommand();
_emcComm.CommandText = ("usp_SearchProduct");
_emcComm.Parameters.AddWithValue("@criteria", _criteria);
_emcComm.CommandType = CommandType.StoredProcedure;
_emcComm.Connection = _conn;
_conn.Open();
AsyncState state = new AsyncState(_emcComm,
controlToBindTo, "command");
PortalSearchDataAsyncHandler productHandler = new
PortalSearchDataAsyncHandler();
return new PageAsyncTask(
new
BeginEventHandler(productHandler.BeginGetSearchData),
new
EndEventHandler(productHandler.EndGetSearchData),
new
EndEventHandler(productHandler.GetSearchDataTimeout),
state, true);

}//end method

I have a data PortalSearchDataAsyncHandler object that contains the
three handler methods required by the PageAsyncTask object. Here is
the code for the async handler methods...

internal IAsyncResult BeginGetSearchData(object src, EventArgs
e, AsyncCallback cb, object state)
{
AsyncState command = state as AsyncState;
return command.Command.BeginExecuteReader(cb, state);
}

internal void EndGetSearchData(IAsyncResult ar)
{

AsyncState commState = ar.AsyncState as AsyncState;

DataTable resultsTable = new DataTable();

SqlDataReader resultsReader =
commState.Command.EndExecuteReader(ar);
try
{
using (resultsReader)
{
resultsTable.Load(resultsReader);
commState.ControlToBindTo.DataSource =
resultsTable;
commState.ControlToBindTo.DataBind();
}
}
finally
{
commState.Command.Connection.Close();
}
}

internal void GetSearchDataTimeout(IAsyncResult ar)
{
AsyncState commState = ar.AsyncState as AsyncState;
// operation timed out, so just clean up by closing the
connection
if (commState.Command.Connection.State ==
ConnectionState.Open)
commState.Command.Connection.Close();
//_messageLabel.Text = "Query timed out...";
}

Anyway I have had to go back to doing all of this synchronously as I
can't believe that the synchronous calls are more efficient in this
case.

Thanks in advance for any help or suggestions,

Cheers

Dermot
 
D

dkil1972

Okay, on brief inspection I don't see anything egregious here, but consider that the async op is only 1/2 (or less) of the operation. Does it make the application faster? Sure it can when applications are held back by operations that can be done in parallel--as it looks like in your case. However,the data fetch is still synchronous.

The exception you're getting is (generally) caused by one of two things:
1.. The code is not closing the connection and releasing it back to theconnection pool. This is not that common any more as most developers have picked up on this issue, but it can creep in if you don't make sure that the connection is released when an exception is fired. Another typical cause of this issue is when passing a DataReader that's not opened with CommandBehavior.CloseConnection. You aren't doing this but I expect you should.
2.. The server is overloaded. That is when the server is asked to perform an operation, it holds the connection until the results are (all) returned. Remember this portion of the operation is synchronous. If another operation comes in before the first is done (as often happens) ADO.NET must create another clone of the connection and put it in the pool. This additional load can slow down the server even more. If this second operation causes the first to block (poor design), you have other issues... If the server never catches up, the pool continues to grow until you reach 100 connections (the default upper limit).
Typically, a heavily used system consumes about 25 connections. With a faster processor(s), more RAM and good design it might make the number lower or higher (capable of keeping the pool small because it's more efficient orcapable of handling more operations per second).

Async ops can buy you some cycles if they were wasted on serializing operations.
Warning: Be sure you don't have MARS enabled--not unless you're absolutely sure you know all of the issues involved.

I'll be discussing this very issue tonight at the Greater New Orleans .NET User Group. I'll be at the Dallas .NET UG the 24th, the Aggieland UG the afternoon of the 25th and San Antonio the 26th. This is also discussed in great depth in my book.

--
____________________________________
William (Bill) Vaughn
Author, Mentor, Consultant
Microsoft MVP
INETA Speakerwww.betav.com/blog/billvawww.betav.com
Please reply only to the newsgroup so that others can benefit.
This posting is provided "AS IS" with no warranties, and confers no rights.
__________________________________
Visitwww.hitchhikerguides.netto get more information on my latest book:
Hitchhiker's Guide to Visual Studio and SQL Server (7th Edition)
and Hitchhiker's Guide to SQL Server 2005 Compact Edition (EBook)
---------------------------------------------------------------------------­--------------------------------------------



dkil1972 said:
In upgrading an application to .Net 2.0 from 1.1 I had an opportunity
to implement some asynchronous calls to the database. In the
application there is a quick search facility that makes 6 calls to 3
different database. This I thought was the perfect scenario for
Asynchronous calls.
Anyway i implemented it and tested it in our win2003 testing
environment calling to a sqlserver instance on the same machine. The
testing worked and I went live with the application. I did not stress
test the application (although i found a nifty stress testing
application which you can get herehttp://www.opensta.org/).
The live environment is also win2003, with the sqlserver instance on a
seperate machine. Soon after deploying to live we started getting the
following error.
The timeout period elapsed prior to obtaining a connection from the
pool. This may have occurred because all pooled connections were in
use and max pool size was reached.
I did some investigating using the stress testing application, which
was set to invoke 100 requests with a 1 second interval on the test
server. Then using Management Studio Activity monitor i checked the
connection activity. Immediately after starting the requests the
number of connections started to rise, in the end it went from 25 upto
180. It took a full minute for that number to start dropping.
I then used Sql Profiler and saw that for each request a new set of 6
connections was being created but these connections are neither reused
nor closed.
Anyway here is the code...
Here i am registering the async task with the page containing the
user control
SearchDataMgr mgr = new SearchDataMgr(_criteria);
Page.RegisterAsyncTask(mgr.GetEmcProductData(product));





All of the getter method calls used as parameters are implemented in
the same way. here is the first one...
public PageAsyncTask GetEmcProductData(BaseDataList
controlToBindTo)
{
string connectionString =
ConfigurationManager.AppSettings["connectionString"].ToString() +
";async=true";
_conn = new SqlConnection(connectionString);
_emcComm = new SqlCommand();
_emcComm.CommandText = ("usp_SearchProduct");
_emcComm.Parameters.AddWithValue("@criteria", _criteria);
_emcComm.CommandType = CommandType.StoredProcedure;
_emcComm.Connection = _conn;
_conn.Open();
AsyncState state = new AsyncState(_emcComm,
controlToBindTo, "command");
PortalSearchDataAsyncHandler productHandler = new
PortalSearchDataAsyncHandler();
return new PageAsyncTask(
new
BeginEventHandler(productHandler.BeginGetSearchData),
new
EndEventHandler(productHandler.EndGetSearchData),
new
EndEventHandler(productHandler.GetSearchDataTimeout),
state, true);
}//end method
I have a data PortalSearchDataAsyncHandler object that contains the
three handler methods required by the PageAsyncTask object. Here is
the code for the async handler methods...
internal IAsyncResult BeginGetSearchData(object src, EventArgs
e, AsyncCallback cb, object state)
{
AsyncState command = state as AsyncState;
return command.Command.BeginExecuteReader(cb, state);
}
internal void EndGetSearchData(IAsyncResult ar)
{
AsyncState commState = ar.AsyncState as AsyncState;
DataTable resultsTable = new DataTable();
SqlDataReader resultsReader =
commState.Command.EndExecuteReader(ar);
try
{
using (resultsReader)
{
resultsTable.Load(resultsReader);
commState.ControlToBindTo.DataSource =
resultsTable;
commState.ControlToBindTo.DataBind();
}
}
finally
{
commState.Command.Connection.Close();
}
}
internal void GetSearchDataTimeout(IAsyncResult ar)
{
AsyncState commState = ar.AsyncState as AsyncState;
// operation timed out, so just clean up by closing the
connection
if (commState.Command.Connection.State ==
ConnectionState.Open)
commState.Command.Connection.Close();
//_messageLabel.Text = "Query timed out...";
}
Anyway I have had to go back to doing all of this synchronously as I
can't believe that the synchronous calls are more efficient in this
case.
Thanks in advance for any help or suggestions,

Dermot- Hide quoted text -

- Show quoted text -

Thank you Bill for your prompt and comprehensive response.

With regard to point 1.
I added the CommandBehavior.CloseConnection enumeration and ensured
that there were no connection leaks from the code. This had no effect,
I viewed the sql profiler and saw lots of initial logins and then the
rpc requests started to complete.

I then tried to put a two second wait state between the calls to
RegisterAsyncTask on the page thus ensuring that a delay was produced
on the database allowing time for all the data to be retrieved.

I suspect that point 2 of your response is correct, The database is
being overloaded and not catching up with demand so the connections
keep growing. The datasets i am dealing with are very small and I
don't think that 6 parallel calls to the database would cause this
much trouble as it is such a small number.

In the end I am not sure as to how I can remedy this issue in the
above code so I have had to go back to synchronous calls. Any further
suggestions would be greatly appreciated.

Thank you for your help

Regards

Dermot
 
W

William \(Bill\) Vaughn

It sounds like you're taking the right steps to diagnose this issue. It does
sound like its a performance issue. I would start looking at the queries to
see if they are cross-locking or serializing themselves. That is, is query A
forcing query B (or C or D) to wait while they work? I would also look at
the query plan for each to ensure that the plans make sense and are tuned
properly. Make sure the right indexes are in place. Make sure that the query
plan still makes sense with the range of input parameters. Consider that the
first invocation of a procedure casts the query plan in plaster (in the
cache) and it's reused (whether or not it's the most efficient plan) until
the cache is flushed or you forcibly recompile it.

hth

--
____________________________________
William (Bill) Vaughn
Author, Mentor, Consultant
Microsoft MVP
INETA Speaker
www.betav.com/blog/billva
www.betav.com
Please reply only to the newsgroup so that others can benefit.
This posting is provided "AS IS" with no warranties, and confers no rights.
__________________________________
Visit www.hitchhikerguides.net to get more information on my latest book:
Hitchhiker's Guide to Visual Studio and SQL Server (7th Edition)
and Hitchhiker's Guide to SQL Server 2005 Compact Edition (EBook)
-----------------------------------------------------------------------------------------------------------------------

Okay, on brief inspection I don't see anything egregious here, but
consider that the async op is only 1/2 (or less) of the operation. Does it
make the application faster? Sure it can when applications are held back
by operations that can be done in parallel--as it looks like in your case.
However, the data fetch is still synchronous.

The exception you're getting is (generally) caused by one of two things:
1.. The code is not closing the connection and releasing it back to the
connection pool. This is not that common any more as most developers have
picked up on this issue, but it can creep in if you don't make sure that
the connection is released when an exception is fired. Another typical
cause of this issue is when passing a DataReader that's not opened with
CommandBehavior.CloseConnection. You aren't doing this but I expect you
should.
2.. The server is overloaded. That is when the server is asked to
perform an operation, it holds the connection until the results are (all)
returned. Remember this portion of the operation is synchronous. If
another operation comes in before the first is done (as often happens)
ADO.NET must create another clone of the connection and put it in the
pool. This additional load can slow down the server even more. If this
second operation causes the first to block (poor design), you have other
issues... If the server never catches up, the pool continues to grow until
you reach 100 connections (the default upper limit).
Typically, a heavily used system consumes about 25 connections. With a
faster processor(s), more RAM and good design it might make the number
lower or higher (capable of keeping the pool small because it's more
efficient or capable of handling more operations per second).

Async ops can buy you some cycles if they were wasted on serializing
operations.
Warning: Be sure you don't have MARS enabled--not unless you're absolutely
sure you know all of the issues involved.

I'll be discussing this very issue tonight at the Greater New Orleans .NET
User Group. I'll be at the Dallas .NET UG the 24th, the Aggieland UG the
afternoon of the 25th and San Antonio the 26th. This is also discussed in
great depth in my book.

--
____________________________________
William (Bill) Vaughn
Author, Mentor, Consultant
Microsoft MVP
INETA Speakerwww.betav.com/blog/billvawww.betav.com
Please reply only to the newsgroup so that others can benefit.
This posting is provided "AS IS" with no warranties, and confers no
rights.
__________________________________
Visitwww.hitchhikerguides.netto get more information on my latest book:
Hitchhiker's Guide to Visual Studio and SQL Server (7th Edition)
and Hitchhiker's Guide to SQL Server 2005 Compact Edition (EBook)
---------------------------------------------------------------------------­--------------------------------------------



dkil1972 said:
In upgrading an application to .Net 2.0 from 1.1 I had an opportunity
to implement some asynchronous calls to the database. In the
application there is a quick search facility that makes 6 calls to 3
different database. This I thought was the perfect scenario for
Asynchronous calls.
Anyway i implemented it and tested it in our win2003 testing
environment calling to a sqlserver instance on the same machine. The
testing worked and I went live with the application. I did not stress
test the application (although i found a nifty stress testing
application which you can get herehttp://www.opensta.org/).
The live environment is also win2003, with the sqlserver instance on a
seperate machine. Soon after deploying to live we started getting the
following error.
The timeout period elapsed prior to obtaining a connection from the
pool. This may have occurred because all pooled connections were in
use and max pool size was reached.
I did some investigating using the stress testing application, which
was set to invoke 100 requests with a 1 second interval on the test
server. Then using Management Studio Activity monitor i checked the
connection activity. Immediately after starting the requests the
number of connections started to rise, in the end it went from 25 upto
180. It took a full minute for that number to start dropping.
I then used Sql Profiler and saw that for each request a new set of 6
connections was being created but these connections are neither reused
nor closed.
Anyway here is the code...
Here i am registering the async task with the page containing the
user control
SearchDataMgr mgr = new SearchDataMgr(_criteria);
Page.RegisterAsyncTask(mgr.GetEmcProductData(product));





All of the getter method calls used as parameters are implemented in
the same way. here is the first one...
public PageAsyncTask GetEmcProductData(BaseDataList
controlToBindTo)
{
string connectionString =
ConfigurationManager.AppSettings["connectionString"].ToString() +
";async=true";
_conn = new SqlConnection(connectionString);
_emcComm = new SqlCommand();
_emcComm.CommandText = ("usp_SearchProduct");
_emcComm.Parameters.AddWithValue("@criteria", _criteria);
_emcComm.CommandType = CommandType.StoredProcedure;
_emcComm.Connection = _conn;
_conn.Open();
AsyncState state = new AsyncState(_emcComm,
controlToBindTo, "command");
PortalSearchDataAsyncHandler productHandler = new
PortalSearchDataAsyncHandler();
return new PageAsyncTask(
new
BeginEventHandler(productHandler.BeginGetSearchData),
new
EndEventHandler(productHandler.EndGetSearchData),
new
EndEventHandler(productHandler.GetSearchDataTimeout),
state, true);
}//end method
I have a data PortalSearchDataAsyncHandler object that contains the
three handler methods required by the PageAsyncTask object. Here is
the code for the async handler methods...
internal IAsyncResult BeginGetSearchData(object src, EventArgs
e, AsyncCallback cb, object state)
{
AsyncState command = state as AsyncState;
return command.Command.BeginExecuteReader(cb, state);
}
internal void EndGetSearchData(IAsyncResult ar)
{
AsyncState commState = ar.AsyncState as AsyncState;
DataTable resultsTable = new DataTable();
SqlDataReader resultsReader =
commState.Command.EndExecuteReader(ar);
try
{
using (resultsReader)
{
resultsTable.Load(resultsReader);
commState.ControlToBindTo.DataSource =
resultsTable;
commState.ControlToBindTo.DataBind();
}
}
finally
{
commState.Command.Connection.Close();
}
}
internal void GetSearchDataTimeout(IAsyncResult ar)
{
AsyncState commState = ar.AsyncState as AsyncState;
// operation timed out, so just clean up by closing the
connection
if (commState.Command.Connection.State ==
ConnectionState.Open)
commState.Command.Connection.Close();
//_messageLabel.Text = "Query timed out...";
}
Anyway I have had to go back to doing all of this synchronously as I
can't believe that the synchronous calls are more efficient in this
case.
Thanks in advance for any help or suggestions,

Dermot- Hide quoted text -

- Show quoted text -

Thank you Bill for your prompt and comprehensive response.

With regard to point 1.
I added the CommandBehavior.CloseConnection enumeration and ensured
that there were no connection leaks from the code. This had no effect,
I viewed the sql profiler and saw lots of initial logins and then the
rpc requests started to complete.

I then tried to put a two second wait state between the calls to
RegisterAsyncTask on the page thus ensuring that a delay was produced
on the database allowing time for all the data to be retrieved.

I suspect that point 2 of your response is correct, The database is
being overloaded and not catching up with demand so the connections
keep growing. The datasets i am dealing with are very small and I
don't think that 6 parallel calls to the database would cause this
much trouble as it is such a small number.

In the end I am not sure as to how I can remedy this issue in the
above code so I have had to go back to synchronous calls. Any further
suggestions would be greatly appreciated.

Thank you for your help

Regards

Dermot
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top