RejectedSoftware Forums

Sign up

Pages: 1 2

how to long poll ?

Hi guys,
I am just investigating how to implement long polling with vibe.

Since I just started using vibe.d I am totally new to the concepts of fibers and the vibe.d API.

But from what I found I thought using a ManualEvent to wait in a http handleRequest until a timeout happens or another fiber triggers an emit on the ManualEvent and then returning the response should do the trick.
The problem is, that when the timeout happens or the emit is triggerd from another fiber (another GET request that is) then the response is not valid anymore.

Any ideas ? Is my whole concept wrong ?

Regards

Re: how to long poll ?

On Wed, 23 Oct 2013 08:32:18 GMT, Stephan Dilly wrote:

Hi guys,
I am just investigating how to implement long polling with vibe.

Since I just started using vibe.d I am totally new to the concepts of fibers and the vibe.d API.

But from what I found I thought using a ManualEvent to wait in a http handleRequest until a timeout happens or another fiber triggers an emit on the ManualEvent and then returning the response should do the trick.
The problem is, that when the timeout happens or the emit is triggerd from another fiber (another GET request that is) then the response is not valid anymore.

Any ideas ? Is my whole concept wrong ?

Regards

I'm not 100% sure what the issue is, but I'd use a TaskCondition instead of a raw ManualEvent to avoid the possibility for accidental race conditions. Just to be on the same page, this is about what I would do:

// possibly __gshared
TaskMutex s_mutex;
TaskCondition s_condition;
bool[Task] s_tasks;

// possibly shared static this
static this()
{
    s_mutex = new TaskMutex;
    s_condition = new TaskCondition;
}

void handleLongPoll(HTTPServerRequest req, HTTPServerResponse res)
{
    auto task = Task.getThis();
    s_tasks[task] = false;
    auto timeout = Clock.currTime(UTC()) + 10.seconds;
    bool timed_out = false;
    synchronized (s_mutex) {
        while (!s_tasks[task]) {
            auto tm = Clock.currTime(UTC());
            timed_out = tm >= timeout;
            if (timed_out) break;
            s_condition.wait(timeout - tm);
        }
        s_tasks.remove(task);
    }
    if (timed_out) {
        // write timeout response
    } else {
        // write normal response
    }
}

void onHandleEvent()
{
    synchronized (s_mutex) {
        foreach (t, ref triggered; s_tasks)
            triggered = true;
    }
    s_condition.notifyAll();
}

Or do you mean that the response is not valid anymore because a connection timeout occurred somewhere? I think such a timeout should only occur in the client, in which case it should be OK. The client would simple have to start another poll request and the server request handler would simply throw an exception and terminate.

Re: how to long poll ?

On Thu, 24 Oct 2013 06:46:05 GMT, Sönke Ludwig wrote:

On Wed, 23 Oct 2013 08:32:18 GMT, Stephan Dilly wrote:

Hi guys,
I am just investigating how to implement long polling with vibe.

Since I just started using vibe.d I am totally new to the concepts of fibers and the vibe.d API.

But from what I found I thought using a ManualEvent to wait in a http handleRequest until a timeout happens or another fiber triggers an emit on the ManualEvent and then returning the response should do the trick.
The problem is, that when the timeout happens or the emit is triggerd from another fiber (another GET request that is) then the response is not valid anymore.

Any ideas ? Is my whole concept wrong ?

Regards

I'm not 100% sure what the issue is, but I'd use a TaskCondition instead of a raw ManualEvent to avoid the possibility for accidental race conditions. Just to be on the same page, this is about what I would do:

// possibly __gshared
TaskMutex s_mutex;
TaskCondition s_condition;
bool[Task] s_tasks;

// possibly shared static this
static this()
{
    s_mutex = new TaskMutex;
    s_condition = new TaskCondition;
}

void handleLongPoll(HTTPServerRequest req, HTTPServerResponse res)
{
    auto task = Task.getThis();
    s_tasks[task] = false;
    auto timeout = Clock.currTime(UTC()) + 10.seconds;
    bool timed_out = false;
    synchronized (s_mutex) {
        while (!s_tasks[task]) {
            auto tm = Clock.currTime(UTC());
            timed_out = tm >= timeout;
            if (timed_out) break;
            s_condition.wait(timeout - tm);
        }
        s_tasks.remove(task);
    }
    if (timed_out) {
        // write timeout response
    } else {
        // write normal response
    }
}

void onHandleEvent()
{
    synchronized (s_mutex) {
        foreach (t, ref triggered; s_tasks)
            triggered = true;
    }
    s_condition.notifyAll();
}

Or do you mean that the response is not valid anymore because a connection timeout occurred somewhere? I think such a timeout should only occur in the client, in which case it should be OK. The client would simple have to start another poll request and the server request handler would simply throw an exception and terminate.

Thanks for you reply, I don't get the stuff you are doing with this aa of Tasks. Why is that necessary ?
What is working for me now is the following solution, but it turns up more questsions :D

class SockJsConnection
{
	TaskMutex mutex;
	TaskCondition condition;
	bool dataPending;
	
	this()
	{
		mutex = new TaskMutex;
		condition = new TaskCondition(mutex);
	}
	
	void handleLongPoll(HTTPServerRequest req, HTTPServerResponse res)
	{
		synchronized (mutex) {
			condition.wait(10.seconds);
		}
		
		if (dataPending) {
			// write timeout response
		} else {
			// write normal response
		}
	}
	
	void write()
	{
		dataPending = true;
		condition.notifyAll();
	}
}

Why do I need to synchronize over the mutex to wait ? I thought vibe.d is using fibers and async io for concurrency ? Can I configure how it scales over multiple threads ?
What's the difference between condition.notify() and condition.notifyAll() - for me the code seems to be exactly the same ;)

Last but not least: Is there a irc channel for D ?
We are seeing a realistic chance to use vibe.d in our company for a server backend, but we would like to be able to shorten the communication routes as much as possible ;)

Re: how to long poll ?

On Thu, 24 Oct 2013 11:19:19 GMT, Stephan Dilly wrote:

Last but not least: Is there a irc channel for D ?

Damn it, I meand for vibe.d, of course I found the D channel but apparently there didn't appear to be much of a support and especially not when it came down to vibe specifics.

Re: how to long poll ?

Am 24.10.2013 13:19, schrieb Stephan Dilly:

On Thu, 24 Oct 2013 06:46:05 GMT, Sönke Ludwig wrote:

On Wed, 23 Oct 2013 08:32:18 GMT, Stephan Dilly wrote:

Hi guys,
I am just investigating how to implement long polling with vibe.

Since I just started using vibe.d I am totally new to the concepts of fibers and the vibe.d API.

But from what I found I thought using a ManualEvent to wait in a http handleRequest until a timeout happens or another fiber triggers an emit on the ManualEvent and then returning the response should do the trick.
The problem is, that when the timeout happens or the emit is triggerd from another fiber (another GET request that is) then the response is not valid anymore.

Any ideas ? Is my whole concept wrong ?

Regards

I'm not 100% sure what the issue is, but I'd use a TaskCondition instead of a raw ManualEvent to avoid the possibility for accidental race conditions. Just to be on the same page, this is about what I would do:
(...)

Thanks for you reply, I don't get the stuff you are doing with this aa of Tasks. Why is that necessary ?

That was just for the case that different tasks have different trigger
conditions. If all are waiting for the same "dataPending" condition,
that is fine, too.

What is working for me now is the following solution, but it turns up more questsions :D

class SockJsConnection
{
	TaskMutex mutex;
	TaskCondition condition;
	bool dataPending;
	
	this()
	{
		mutex = new TaskMutex;
		condition = new TaskCondition(mutex);
	}
	
	void handleLongPoll(HTTPServerRequest req, HTTPServerResponse res)
	{
		synchronized (mutex) {
			condition.wait(10.seconds);
		}
		
		if (dataPending) {
			// write timeout response
		} else {
			// write normal response
		}
	}
	
	void write()
	{
		dataPending = true;
		condition.notifyAll();
	}
}

Why do I need to synchronize over the mutex to wait ? I thought vibe.d is using fibers and async io for concurrency ? Can I configure how it scales over multiple threads ?

That's the standard protocol for condition variables, which ensures that
checking the condition happens atomically. This avoids that a
notification is missed while checking the condition. The following shows
how threads (or tasks, if I/O is involved) may get interleaved by the
scheduler so that a notification is missed and thread 1 waits longer
than expected.

thread 1                        thread 2
check if data available -> no
                                 set data available to yes
                                 notify
wait for notification

A similar condition can occur in your code if dataPending is already
true before condition.wait() is called.

So you should at least use

synchronized (mutex) {
	if (!dataPending)
		condition.wait(10.seconds);
}

As long as no threads are involved, and no I/O happens between checking
the condition and waiting (or between setting dataPending and
notifyAll()) the mutex is not strictly necessary, but should
multi-threading ever be needed for performance scaling, it's good to
have the correct code already there.

What's the difference between condition.notify() and condition.notifyAll() - for me the code seems to be exactly the same ;)

The current implementation is sub optimal, but the idea is that
notify() will only wake up one task/thread that waits for the
condition, while notifyAll() wakes up all of them. So notify is
useful e.g. when multiple worker threads are waiting on a single
condition, but only one work item is added to the queue.

Last but not least: Is there a irc channel for D ?
We are seeing a realistic chance to use vibe.d in our company for a server backend, but we would like to be able to shorten the communication routes as much as possible ;)

There is no IRC channel for vibe.d AFAIK. I'm usually pretty responsive
on the forums, though (IRC wouldn't really be better in that regard),
but currently I'm a bit overloaded with communication.

Re: how to long poll ?

On Thu, 24 Oct 2013 14:26:46 +0200, Sönke Ludwig wrote:

Am 24.10.2013 13:19, schrieb Stephan Dilly:

On Thu, 24 Oct 2013 06:46:05 GMT, Sönke Ludwig wrote:

On Wed, 23 Oct 2013 08:32:18 GMT, Stephan Dilly wrote:

Hi guys,
I am just investigating how to implement long polling with vibe.

Since I just started using vibe.d I am totally new to the concepts of fibers and the vibe.d API.

But from what I found I thought using a ManualEvent to wait in a http handleRequest until a timeout happens or another fiber triggers an emit on the ManualEvent and then returning the response should do the trick.
The problem is, that when the timeout happens or the emit is triggerd from another fiber (another GET request that is) then the response is not valid anymore.

Any ideas ? Is my whole concept wrong ?

Regards

I'm not 100% sure what the issue is, but I'd use a TaskCondition instead of a raw ManualEvent to avoid the possibility for accidental race conditions. Just to be on the same page, this is about what I would do:
(...)

Thanks for you reply, I don't get the stuff you are doing with this aa of Tasks. Why is that necessary ?

That was just for the case that different tasks have different trigger
conditions. If all are waiting for the same "dataPending" condition,
that is fine, too.

What is working for me now is the following solution, but it turns up more questsions :D

class SockJsConnection
{
	TaskMutex mutex;
	TaskCondition condition;
	bool dataPending;
	
	this()
	{
		mutex = new TaskMutex;
		condition = new TaskCondition(mutex);
	}
	
	void handleLongPoll(HTTPServerRequest req, HTTPServerResponse res)
	{
		synchronized (mutex) {
			condition.wait(10.seconds);
		}
		
		if (dataPending) {
			// write timeout response
		} else {
			// write normal response
		}
	}
	
	void write()
	{
		dataPending = true;
		condition.notifyAll();
	}
}

Why do I need to synchronize over the mutex to wait ? I thought vibe.d is using fibers and async io for concurrency ? Can I configure how it scales over multiple threads ?

That's the standard protocol for condition variables, which ensures that
checking the condition happens atomically. This avoids that a
notification is missed while checking the condition. The following shows
how threads (or tasks, if I/O is involved) may get interleaved by the
scheduler so that a notification is missed and thread 1 waits longer
than expected.

thread 1                        thread 2
check if data available -> no
                                 set data available to yes
                                 notify
wait for notification

A similar condition can occur in your code if dataPending is already
true before condition.wait() is called.

So you should at least use

synchronized (mutex) {
	if (!dataPending)
		condition.wait(10.seconds);
}

As long as no threads are involved, and no I/O happens between checking
the condition and waiting (or between setting dataPending and
notifyAll()) the mutex is not strictly necessary, but should
multi-threading ever be needed for performance scaling, it's good to
have the correct code already there.

What's the difference between condition.notify() and condition.notifyAll() - for me the code seems to be exactly the same ;)

The current implementation is sub optimal, but the idea is that
notify() will only wake up one task/thread that waits for the
condition, while notifyAll() wakes up all of them. So notify is
useful e.g. when multiple worker threads are waiting on a single
condition, but only one work item is added to the queue.

Last but not least: Is there a irc channel for D ?
We are seeing a realistic chance to use vibe.d in our company for a server backend, but we would like to be able to shorten the communication routes as much as possible ;)

There is no IRC channel for vibe.d AFAIK. I'm usually pretty responsive
on the forums, though (IRC wouldn't really be better in that regard),
but currently I'm a bit overloaded with communication.

Thanks a lot!

The first very early release of my sockjs-d module for vibe works now. Awesome this is the first stepping stone on converting our server from java to vibe.d.

Re: how to long poll ?

On Thu, 24 Oct 2013 16:55:20 GMT, Stephan Dilly wrote:

On Thu, 24 Oct 2013 14:26:46 +0200, Sönke Ludwig wrote:

Am 24.10.2013 13:19, schrieb Stephan Dilly:

On Thu, 24 Oct 2013 06:46:05 GMT, Sönke Ludwig wrote:

On Wed, 23 Oct 2013 08:32:18 GMT, Stephan Dilly wrote:

Hi guys,
I am just investigating how to implement long polling with vibe.

Since I just started using vibe.d I am totally new to the concepts of fibers and the vibe.d API.

But from what I found I thought using a ManualEvent to wait in a http handleRequest until a timeout happens or another fiber triggers an emit on the ManualEvent and then returning the response should do the trick.
The problem is, that when the timeout happens or the emit is triggerd from another fiber (another GET request that is) then the response is not valid anymore.

Any ideas ? Is my whole concept wrong ?

Regards

I'm not 100% sure what the issue is, but I'd use a TaskCondition instead of a raw ManualEvent to avoid the possibility for accidental race conditions. Just to be on the same page, this is about what I would do:
(...)

Thanks for you reply, I don't get the stuff you are doing with this aa of Tasks. Why is that necessary ?

That was just for the case that different tasks have different trigger
conditions. If all are waiting for the same "dataPending" condition,
that is fine, too.

What is working for me now is the following solution, but it turns up more questsions :D

class SockJsConnection
{
	TaskMutex mutex;
	TaskCondition condition;
	bool dataPending;
	
	this()
	{
		mutex = new TaskMutex;
		condition = new TaskCondition(mutex);
	}
	
	void handleLongPoll(HTTPServerRequest req, HTTPServerResponse res)
	{
		synchronized (mutex) {
			condition.wait(10.seconds);
		}
		
		if (dataPending) {
			// write timeout response
		} else {
			// write normal response
		}
	}
	
	void write()
	{
		dataPending = true;
		condition.notifyAll();
	}
}

Why do I need to synchronize over the mutex to wait ? I thought vibe.d is using fibers and async io for concurrency ? Can I configure how it scales over multiple threads ?

That's the standard protocol for condition variables, which ensures that
checking the condition happens atomically. This avoids that a
notification is missed while checking the condition. The following shows
how threads (or tasks, if I/O is involved) may get interleaved by the
scheduler so that a notification is missed and thread 1 waits longer
than expected.

thread 1                        thread 2
check if data available -> no
                                 set data available to yes
                                 notify
wait for notification

A similar condition can occur in your code if dataPending is already
true before condition.wait() is called.

So you should at least use

synchronized (mutex) {
	if (!dataPending)
		condition.wait(10.seconds);
}

As long as no threads are involved, and no I/O happens between checking
the condition and waiting (or between setting dataPending and
notifyAll()) the mutex is not strictly necessary, but should
multi-threading ever be needed for performance scaling, it's good to
have the correct code already there.

What's the difference between condition.notify() and condition.notifyAll() - for me the code seems to be exactly the same ;)

The current implementation is sub optimal, but the idea is that
notify() will only wake up one task/thread that waits for the
condition, while notifyAll() wakes up all of them. So notify is
useful e.g. when multiple worker threads are waiting on a single
condition, but only one work item is added to the queue.

Last but not least: Is there a irc channel for D ?
We are seeing a realistic chance to use vibe.d in our company for a server backend, but we would like to be able to shorten the communication routes as much as possible ;)

There is no IRC channel for vibe.d AFAIK. I'm usually pretty responsive
on the forums, though (IRC wouldn't really be better in that regard),
but currently I'm a bit overloaded with communication.

Thanks a lot!

The first very early release of my sockjs-d module for vibe works now. Awesome this is the first stepping stone on converting our server from java to vibe.d.

I had to make a weird change to make the timeout of the wait condition work. please have a look at this commit.
why do i have to trigger the condition by an additional timer instead of being able to use the wait timeout parameter ? Cause if I use it, then exactly after the timeout is over all kinds of access violations happen inside of vibe.d and it is talking about invalid locks...

Any ideas ?

Re: how to long poll ?

On Fri, 25 Oct 2013 22:09:21 GMT, Stephan Dilly wrote:

On Thu, 24 Oct 2013 16:55:20 GMT, Stephan Dilly wrote:

On Thu, 24 Oct 2013 14:26:46 +0200, Sönke Ludwig wrote:

Am 24.10.2013 13:19, schrieb Stephan Dilly:

On Thu, 24 Oct 2013 06:46:05 GMT, Sönke Ludwig wrote:

On Wed, 23 Oct 2013 08:32:18 GMT, Stephan Dilly wrote:

Hi guys,
I am just investigating how to implement long polling with vibe.

Since I just started using vibe.d I am totally new to the concepts of fibers and the vibe.d API.

But from what I found I thought using a ManualEvent to wait in a http handleRequest until a timeout happens or another fiber triggers an emit on the ManualEvent and then returning the response should do the trick.
The problem is, that when the timeout happens or the emit is triggerd from another fiber (another GET request that is) then the response is not valid anymore.

Any ideas ? Is my whole concept wrong ?

Regards

I'm not 100% sure what the issue is, but I'd use a TaskCondition instead of a raw ManualEvent to avoid the possibility for accidental race conditions. Just to be on the same page, this is about what I would do:
(...)

Thanks for you reply, I don't get the stuff you are doing with this aa of Tasks. Why is that necessary ?

That was just for the case that different tasks have different trigger
conditions. If all are waiting for the same "dataPending" condition,
that is fine, too.

What is working for me now is the following solution, but it turns up more questsions :D

class SockJsConnection
{
	TaskMutex mutex;
	TaskCondition condition;
	bool dataPending;
	
	this()
	{
		mutex = new TaskMutex;
		condition = new TaskCondition(mutex);
	}
	
	void handleLongPoll(HTTPServerRequest req, HTTPServerResponse res)
	{
		synchronized (mutex) {
			condition.wait(10.seconds);
		}
		
		if (dataPending) {
			// write timeout response
		} else {
			// write normal response
		}
	}
	
	void write()
	{
		dataPending = true;
		condition.notifyAll();
	}
}

Why do I need to synchronize over the mutex to wait ? I thought vibe.d is using fibers and async io for concurrency ? Can I configure how it scales over multiple threads ?

That's the standard protocol for condition variables, which ensures that
checking the condition happens atomically. This avoids that a
notification is missed while checking the condition. The following shows
how threads (or tasks, if I/O is involved) may get interleaved by the
scheduler so that a notification is missed and thread 1 waits longer
than expected.

thread 1                        thread 2
check if data available -> no
                                 set data available to yes
                                 notify
wait for notification

A similar condition can occur in your code if dataPending is already
true before condition.wait() is called.

So you should at least use

synchronized (mutex) {
	if (!dataPending)
		condition.wait(10.seconds);
}

As long as no threads are involved, and no I/O happens between checking
the condition and waiting (or between setting dataPending and
notifyAll()) the mutex is not strictly necessary, but should
multi-threading ever be needed for performance scaling, it's good to
have the correct code already there.

What's the difference between condition.notify() and condition.notifyAll() - for me the code seems to be exactly the same ;)

The current implementation is sub optimal, but the idea is that
notify() will only wake up one task/thread that waits for the
condition, while notifyAll() wakes up all of them. So notify is
useful e.g. when multiple worker threads are waiting on a single
condition, but only one work item is added to the queue.

Last but not least: Is there a irc channel for D ?
We are seeing a realistic chance to use vibe.d in our company for a server backend, but we would like to be able to shorten the communication routes as much as possible ;)

There is no IRC channel for vibe.d AFAIK. I'm usually pretty responsive
on the forums, though (IRC wouldn't really be better in that regard),
but currently I'm a bit overloaded with communication.

Thanks a lot!

The first very early release of my sockjs-d module for vibe works now. Awesome this is the first stepping stone on converting our server from java to vibe.d.

I had to make a weird change to make the timeout of the wait condition work. please have a look at this commit.
why do i have to trigger the condition by an additional timer instead of being able to use the wait timeout parameter ? Cause if I use it, then exactly after the timeout is over all kinds of access violations happen inside of vibe.d and it is talking about invalid locks...

Any ideas ?

Dicebot adviced me in the irc to bump my question again with a "pretty please" :)

Re: how to long poll ?

Am 28.10.2013 17:41, schrieb Stephan Dilly:

On Fri, 25 Oct 2013 22:09:21 GMT, Stephan Dilly wrote:

I had to make a weird change to make the timeout of the wait condition work. please have a look at this commit.
why do i have to trigger the condition by an additional timer instead of being able to use the wait timeout parameter ? Cause if I use it, then exactly after the timeout is over all kinds of access violations happen inside of vibe.d and it is talking about invalid locks...

Any ideas ?

Dicebot adviced me in the irc to bump my question again with a "pretty please" :)

Sorry, I missed this. I'd have to reproduce that locally to be able to
make a qualified statement. Given that I check out the commit before the
one you linked, what exactly do I have to do to trigger the errors?

Re: how to long poll ?

On Mon, 28 Oct 2013 17:53:46 +0100, Sönke Ludwig wrote:

Am 28.10.2013 17:41, schrieb Stephan Dilly:

On Fri, 25 Oct 2013 22:09:21 GMT, Stephan Dilly wrote:

I had to make a weird change to make the timeout of the wait condition work. please have a look at this commit.
why do i have to trigger the condition by an additional timer instead of being able to use the wait timeout parameter ? Cause if I use it, then exactly after the timeout is over all kinds of access violations happen inside of vibe.d and it is talking about invalid locks...

Any ideas ?

Dicebot adviced me in the irc to bump my question again with a "pretty please" :)

Sorry, I missed this. I'd have to reproduce that locally to be able to
make a qualified statement. Given that I check out the commit before the
one you linked, what exactly do I have to do to trigger the errors?

Yeah just sync to the previous commit: https://github.com/Extrawurst/sockjs-d/commit/3b05c779fde9104283288e0453edfe862246f5eb
Then start the app and open your browser on http://localhost:8989/index.html
You should see the POST comming in in the log and see that after the heartbeat interval (25s in default) the connection should return and expect the client to newly connect: https://github.com/Extrawurst/sockjs-d/blob/3b05c779fde9104283288e0453edfe862246f5eb/source/sockjs/connection.d#L129

Well after this timeout all kinds of exceptions are thrown from inside vibe.d... for example some stuff i see when using "--vv" cmd line:
[02090F80:020FE400 CRITICAL] CoreTaskFiber was terminated unexpectedly: Privileged Instruction
[02090F80:020FE400 dia] Full error: object.Error: Privileged Instruction
[02090F80:020FE400 dia] ----------------
[02090F80:020FE400 dia] 0x005B5B1D in TypeInfoP_init
[02090F80:020FE400 dia] 0x004F22A5 in corethreadFiberrun
[02090F80:020FE400 dia] 0xFFFFFFFF
[02090F80:020FE400 dia] 0x77B771F5 in WinSqmSetIfMaxDWORD

And the first two exceptions are:
[02090F80:02090000 CRITICAL] CoreTaskFiber was terminated unexpectedly: Array Bounds Exceeded
[02090F80:02090000 dia] Full error: object.Error: Array Bounds Exceeded
[02090F80:02090000 dia] ----------------
[02090F80:02090000 dia] 0x005B5B8D in TypeInfoP_vtbl
[02090F80:02090000 dia] 0x004F22A5 in corethreadFiberrun
[02090F80:02090000 dia] 0xFFFFFFFF
[02090F80:02090000 dia] 0x77B771F5 in WinSqmSetIfMaxDWORD

And sometimes there is an AccessViolation too...

Hope you can find something in there... Seems pretty tedios that this solution does not work and that I have to start an additional timer to do the timeout...

Pages: 1 2