Hi all!
I make vibe-d based project and now I have problem passing
messages between threads.
First some words about architecture. Each event in the system has
a corresponding class that validates and performs the required
actions. Each class has a nested structure with the parameters
that are required for this event. Like this:
```
module vcm.bll.event.deleteSite;
import vcm.bll.basicEvent;
class DeleteSite : BasicEvent
{
import vcm.bll.model.types : Id;
struct Params
{
Id siteId;
}
mixin EventConstructor;
override bool canDo()
{
import std.conv : to;
return errorList
.addIf(!engine.sites.contains(params.siteId), "SiteModel with
id "~params.siteId.to!string~" is not found")
.isEmpty();
}
override EventResult doIt()
{
engine.db.execute("DELETE FROM sites WHERE id=?",
params.siteId);
return EventResult(true,[],0);
}
}
```
I have Engine class object which resides in own thread and listen
message queue for messages with event parameters. After receiving
message corresponding handler is executed, and message with
EventResult object sent back to caller thread (Task). For every
event type there is HTTP request handler, who make
EventType.Params structure, send it to engine Task, then do
receiveOnly!EventResult and take actions according to it. The
only proble with this approach was a lot of boilerplate in engine
receive() call because of big amout of event types. I resolve it
by this way (is this possible without string mixin?):
```
private static string getReceiver(EventTypes...)() pure
{
import std.traits;
string eventHandlers;
foreach(EventType; EventTypes)
eventHandlers ~= `,(`~EventType.stringof~`.Params params, Task
caller, Id userId){
auto event =
scoped!`~EventType.stringof~`(userId, params);
event.setEngine(this);
caller.send(event.execute());
}`;
return
`receive
((ExitMessage _){ exitFlag = true; }
,(LogMessage entry){ logger.log(entry.message);
}
`
~eventHandlers
~");";
}
private void run()
{
import vibe.core.concurrency : receive, send;
import std.typecons: scoped;
import vcm.bll.event;
bool exitFlag = false;
while(!exitFlag)
mixin(getReceiver!AllEvents);
}
```
After adding another event I ran into a problem:
```
Task terminated with unhandled exception: Range violation
core.exception.RangeError@source/vcm/bll/idContainer.d(44): Range
violation
----------------
...
vcm.bll.event.deleteSite.DeleteSite.canDo() [0xd8dd5a]
source/vcm/bll/basicEvent.d:182 bool
vcm.bll.basicEvent.BasicEvent.check() [0xd2f8bc]
source/vcm/bll/basicEvent.d:197 vcm.bll.basicEvent.EventResult
vcm.bll.basicEvent.BasicEvent.execute() [0xd2f9a5]
source/vcm/bll/engine.d-mixin-173:198
_D3vcm3bll6engine6Engine3runMFZ9__lambda8MFS3vcm3bll5event10deleteSite10DeleteSite6ParamsS4vibe4core4task4TaskmZv [0xd34375]
/usr/include/dmd/phobos/std/concurrency.d:168 void
std.concurrency.Message.map!(void
delegate(vcm.bll.event.deleteSite.DeleteSite.Params,
vibe.core.task.Task, ulong)).map(void
delegate(vcm.bll.event.deleteSite.DeleteSite.Params,
vibe.core.task.Task, ulong)) [0xc7df3d]
/usr/include/dmd/phobos/std/concurrency.d:1956
_D3std11concurrency10MessageBox1467__T3getTDFNaNbNiNfS3vcm3bll7commons11ExitMessageZvTDFS3vcm3bll6engine10LogMessageZvTDFS3vcm3bll5event9addDevice9AddDevice6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event9addClient9AddClient6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event7addRole7AddRole6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event7addUser7AddUser6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event7addSite7AddSite6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event10deleteSite10DeleteSite6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event13adminEditUser13AdminEditUser6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event14changePassword14ChangePassword6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event12deleteDevice12DeleteDevice6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event10deleteRole10DeleteRole6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event10deleteUser10DeleteUser6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event10editDevice10EditDevice6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3!
bll5event5login5Login6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event8register8Register6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event11adminLogout11AdminLogout6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event15adminEditClient15AdminEditClient6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event9importMdb9ImportMdb6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event12deleteClient12DeleteClient6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event18managerIncludeUser18ManagerIncludeUser6ParamsS4vibe4core
/usr/include/dmd/phobos/std/concurrency.d:2037
_D3std11concurrency10MessageBox1467__T3getTDFNaNbNiNfS3vcm3bll7commons11ExitMessageZvTDFS3vcm3bll6engine10LogMessageZvTDFS3vcm3bll5event9addDevice9AddDevice6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event9addClient9AddClient6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event7addRole7AddRole6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event7addUser7AddUser6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event7addSite7AddSite6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event10deleteSite10DeleteSite6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event13adminEditUser13AdminEditUser6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event14changePassword14ChangePassword6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event12deleteDevice12DeleteDevice6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event10deleteRole10DeleteRole6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event10deleteUser10DeleteUser6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event10editDevice10EditDevice6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3!
bll5event5login5Login6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event8register8Register6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event11adminLogout11AdminLogout6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event15adminEditClient15AdminEditClient6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event9importMdb9ImportMdb6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event12deleteClient12DeleteClient6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event18managerIncludeUser18ManagerIncludeUser6ParamsS4vibe4core
/usr/include/dmd/phobos/std/concurrency.d:2115 bool
std.concurrency.MessageBox.get!(pure nothrow @nogc @safe void
delegate(vcm.bll.commons.ExitMessage), void
delegate(vcm.bll.engine.LogMessage), void
delegate(vcm.bll.event.addDevice.AddDevice.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.addClient.AddClient.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.addRole.AddRole.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.addUser.AddUser.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.addSite.AddSite.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.deleteSite.DeleteSite.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.adminEditUser.AdminEditUser.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.changePassword.ChangePassword.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.deleteDevice.DeleteDevice.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.deleteRole.DeleteRole.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.deleteUser.DeleteUser.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.editDevice.EditDevice.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.login.Login.Params, vibe.core.task.Task,
ulong), void delegate(vcm.bll.event.register.Register.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.adminLogout.AdminLogout.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.adminEditClient.AdminEd
/usr/include/dmd/phobos/std/concurrency.d:700 void
std.concurrency.receive!(pure nothrow @nogc @safe void
delegate(vcm.bll.commons.ExitMessage), void
delegate(vcm.bll.engine.LogMessage), void
delegate(vcm.bll.event.addDevice.AddDevice.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.addClient.AddClient.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.addRole.AddRole.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.addUser.AddUser.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.addSite.AddSite.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.deleteSite.DeleteSite.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.adminEditUser.AdminEditUser.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.changePassword.ChangePassword.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.deleteDevice.DeleteDevice.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.deleteRole.DeleteRole.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.deleteUser.DeleteUser.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.editDevice.EditDevice.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.login.Login.Params, vibe.core.task.Task,
ulong), void delegate(vcm.bll.event.register.Register.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.adminLogout.AdminLogout.Params,
vibe.core.task.Task, ulong), void
delegate(vcm.bll.event.adminEditClient.AdminEditClient
source/vcm/bll/engine.d:172 void vcm.bll.engine.Engine.run()
[0xd33c66]
../../.dub/packages/vibe-d-0.7.30/vibe-d/source/vibe/core/core.d:592 void
vibe.core.core.makeTaskFuncInfo!(void delegate()).makeTaskFuncInfo(ref void
delegate()).callDelegate(vibe.core.core.TaskFuncInfo*) [0xc2b8fc]
../../.dub/packages/vibe-d-0.7.30/vibe-d/source/vibe/core/core.d:1221 void
vibe.core.core.CoreTask.run() [0xf2ecc6]
??:? void core.thread.Fiber.run() [0x103f65f]
??:? fiber_entryPoint [0x103f3c2]
??:? [0xffffffff]
core.exception.InvalidMemoryOperationError@src/core/exception.d(693): Invalid
memory operation
----------------
```
The problem here - not the exception itself, but the fact that
the stack consists a call to void
delegate(vcm.bll.event.deleteSite.DeleteSite.Params, ...) because
I am quite sure that the parameter passed is
ManagerIncludeUser.Params. I see very long symbols in the stack
trace. Is this possible I hit some restriction on the length of
the symbol or the number of delegates in receive() and it leads
to broken mapping?