Search code examples
c#connection-timeout

Timeout expired Exception; Can't find which connection is left open or if there is something else wrong


I'm getting "Timeout expired. 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." error, but can't find where is the problem. Little help, please. :)

public static void Update(string p, int c)
    {
        using (SqlConnection conn = new SqlConnection("ConnectionString"))
        {
            SqlCommand cmd = new SqlCommand();
            SqlDataReader myRdr;

            cmd.Connection = conn;
            cmd.CommandText = "SOME SQL QUERY @parameter";
            cmd.CommandType = CommandType.Text;
            cmd.Parameters.Add("@parameter", SqlDbType.NVarChar, 10).Value = p;

            conn.Open();
            myRdr = cmd.ExecuteReader();

            if (myRdr.HasRows)
            {
                while (myRdr.Read())
                {
                    //do something using myRdr data
                }
                myRdr.Close();
                cmd.Dispose();

                foreach (DataRow r in dt.Rows)
                {
                    SqlCommand cmd1 = new SqlCommand();

                    cmd1.Connection = conn;
                    cmd1.CommandText = "SOME SQL QUERY @parameter";
                    cmd1.CommandType = CommandType.Text;
                    cmd1.Parameters.Add("@parameter", SqlDbType.NVarChar, 10).Value = r["SomeData"];

                    myRdr = cmd1.ExecuteReader();
                    myRdr.Read();

                    //do something with myRdr data

                    myRdr.Close();
                    cmd1.Dispose();

                    int a = Convert.ToInt32(r["SomeData"]) - Convert.ToInt32(r["SomeData1"]);

                    if (a >= 0)
                    {
                        //do something
                    }
                    else
                    {
                        //do something else and runn the Update() again with some other parameters

                        Update(x, y); //I think here is some problem...
                                      //because when this condition is not met and program 
                                      //does not need to run Update() again, it goes OK and I get no error
                    }
                }
            }
            else
            {
                myRdr.Close();
                cmd.Dispose();
            }
        }
    }

Solution

  • You should cosider moving your call to Update(x,y) somewhere outside the outer using() block.

    Calling it from the inside using means you're establishing another connection to the same database without first freeing the outer one. If you get number of recursive calls then you'll run out of free connections VERY quickly.

    In general, using recursion calls in parts of code dealing with databases is considered a very bad practice.

    If you REALLY need this recursion here then still it should be done outside the outer using. I'd suggest caching your x,y in some kind of collection and issuing the calls to Update(x,y) by traversing this collection outside the using block, like this :

    public static void Update(string p, int c)
    {
        // I'd suggest Dictionary, but don't know whether your strings are unique
        var recursionParameters = new List<KeyValuePair<string, int>>(); 
    
        using (SqlConnection conn = new SqlConnection("ConnectionString"))
        {
            ...
                        //do something else and runn the Update() again with some other parameters
    
                        //Update(x, y); Don't do it here! Instead:
                        recursionParameters.Add(new KeyValuePair<string, int>(x,y));
            ...
        }
        foreach (var kvp in recursionParameters
        {
            Update(kvp.Key, kvp.Value)
        }
    }