0

I'm developing a game. In this game player can click on a button and attack a boss, and he has to wait 5 minutes for the results of the attack.The attack will be executed only after 5 minutes.
So here is my try: here is my function which is called when the button is clicked:

public static void InsertNewWaitingAttack(string attacker_id, string boss_id, DateTime  start, DateTime done)
{
    string sql = "INSERT INTO WaitingAttacks (AttackerID,BossID,AttackTime,DoneTime) VALUES (@A_ID,@B_ID,@Start,@Done); ";
    sql += "WAITFOR DELAY '000:05:00'; ";
    sql += "INSERT INTO BossAttacks (AttackerID,BossID,AttackTime,Damage) VALUES (@A_ID,@B_ID,@Start,@Damage); ";
    sql += "DELETE FROM WaitingAttacks WHERE AttackerID=@A_ID AND AttackTime=@Start;";
    SqlConnection sc = new SqlConnection(conString);
    using (SqlCommand cmd = new SqlCommand(sql, sc))
    {
        cmd.Parameters.AddWithValue("A_ID", attacker_id);
        cmd.Parameters.AddWithValue("B_ID", boss_id);
        cmd.Parameters.AddWithValue("Start", start);
        cmd.Parameters.AddWithValue("Done", done);
        cmd.Parameters.AddWithValue("Damage", 500);
        sc.Open();
        cmd.ExecuteNonQuery();
        sc.Close();
    }
}

But when I'm calling this function I'm getting the following error:

Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.

EDIT: To clarify my question, this is an asp.net application. The solution should consider that the server should serve multiple clients.
if the user enters the "Result page" before the execution of the attack, he will see countdown to the execution of the attack.(Which means that the start time of the attack should always be accessible.)
EDIT #2:
The question is still relevant. I didn't find any solution yet.

Omer Eldan
  • 1,757
  • 1
  • 11
  • 10
  • 7
    I suggest doing the delay in-code rather than in your SQL statement. – dav_i Nov 11 '13 at 10:38
  • 5
    to be clear: `waitfor` *suspends the spid*; your sql command will therefore take 5 minutes and a tiny fraction. It should not be a surprise that it times out. – Marc Gravell Nov 11 '13 at 10:40
  • 5
    How to answer this depends a lot on the overall design. You could use `Task.Delay`, but I wonder if a better idea here is "insert the attack into the database or some queue, with a future date - only process it when the date comes into scope" – Marc Gravell Nov 11 '13 at 10:42
  • can't I only send a query, and it will be executed after 5 minutes? @MarcGravell – Omer Eldan Nov 11 '13 at 11:14
  • @OmerEldan no, basically – Marc Gravell Nov 11 '13 at 13:43

2 Answers2

4

How about setting a timer in your code that fires after 5 minutes and performs the INSERT without WAITFOR? That way, the program remains responsive and you still get a delay.

I suggest you use System.Timers.Timer as it runs in a separate thread and can also more easily be configured to be a "one shot" timer.


Another possible way that would make handling multiple boss attach easier would be to create a list of pending "boss attacks" and have a threaded timer work on that list like this:

private class BossAttack
{
    public DateTime AttackTime;
    //... Other properties
}

List<BossAttack> pendingAttacks = new List<BossAttack>();

// Adding a boss attack
lock (pendingAttacks)
{
    pendingAttacks.Add(new BossAttack()
    {
         AttackTime = DateTime.Now;
         ...
    }
}

The timer could run every second, get all boss attacks older than 5 minutes and process them:

var currentAttacks = (from a in pendingAttacks where (DateTime.Now - a.AttackTime).TotalMinutes() >= 5 select a);
foreach (var currentAttack in currentAttacks)
    //...
Thorsten Dittmar
  • 55,956
  • 8
  • 91
  • 139
  • This seems like an elegant solution - although if it's on a per user basis would having lots of timers cause a problem? – Ian Nov 11 '13 at 10:43
  • What do you mean on a per user basis? One player plays the game, and clicks the button - where's the overhead? This is not running on a server, this is running on a client. – Thorsten Dittmar Nov 11 '13 at 10:44
  • @ThorstenDittmar games running *just* on a client usually don't need a full SQL Server install... I don't think we have enough context to fully know much here. – Marc Gravell Nov 11 '13 at 10:45
  • 1
    I guess I'm making an assumption. This is web based so you'd expect a server serving multiple clients, and hence you'd not normally epxect processing to be on the client. – Ian Nov 11 '13 at 10:45
  • @MarcGravell Right. Didn't consider that. I'm going to improve my answer. – Thorsten Dittmar Nov 11 '13 at 10:48
  • Actually this solution seems to be correct,but running this timer every second 24/7 will not take alot of resources? @ThorstenDittmar – Omer Eldan Nov 11 '13 at 11:00
  • I guess that will depend on the interval. Of course, a timer running every second will use more processor time than a timer running every minute. We have several windows services running at customer sites that have more than one timer running every second and it has never been visibly significant to CPU usage. – Thorsten Dittmar Nov 11 '13 at 11:15
  • @ThorstenDittmar should I store this list in an Application["blabla"]? – Omer Eldan Nov 11 '13 at 11:52
  • I'm not really sure what an `Application["blabla"]` is... I'd make the project so that there is a windows service that does all the background work and the ASP project communicates only with that service. – Thorsten Dittmar Nov 11 '13 at 12:06
  • @ThorstenDittmar The problem is that my website is on a shared hosting and I cannot use Windows services. The other option is to create an exe file and set a scedule task for every 1 second, but the shortest period that i can set is every 1 minute. What should I do? – Omer Eldan Nov 11 '13 at 12:43
  • Naaah, not an EXE! Actually I'm not to experiences with ASP.NET to provide a qualified answer ;-) – Thorsten Dittmar Nov 11 '13 at 12:48
-2

You can try System.Threading.Sleep in an async why see the answer in here:

Asynchronous Thread.Sleep()

Community
  • 1
  • 1
amrswalha
  • 372
  • 8
  • 20