www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Problem with send / receive

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__lambda8MFS3vcm3bll5event10deleteSite10DeleteSite6ParamsS4vi
e4core4task4TaskmZv [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__T3getTDFNaNbNiNfS3vcm3bll7commons11ExitMessageZvTDFS3vcm3bll6engine10LogMessageZvTDFS3vcm3bll5event9addDevice9AddDevice6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event9addClient9AddClient6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event7addRole7AddRole6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event7addUser7AddUser6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event7addSite7AddSite6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event10deleteSite10DeleteSite6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event13adminEditUser13AdminEditUser6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event14changePassword14ChangePassword6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event12deleteDevice12DeleteDevice6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event10deleteRole10DeleteRole6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event10deleteUser10DeleteUser6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event10editDevice10EditDevice6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event5login5Login6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event8register8Register6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event11adminLogout11AdminLogout6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event15adminEditClient15AdminEditClient6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event9importMdb9ImportMdb6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event12deleteClient12DeleteClient6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event18managerIncludeUser18ManagerIncludeUser6ParamsS4vibe4core
/usr/include/dmd/phobos/std/concurrency.d:2037 
_D3std11concurrency10MessageBox1467__T3getTDFNaNbNiNfS3vcm3bll7commons11ExitMessageZvTDFS3vcm3bll6engine10LogMessageZvTDFS3vcm3bll5event9addDevice9AddDevice6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event9addClient9AddClient6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event7addRole7AddRole6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event7addUser7AddUser6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event7addSite7AddSite6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event10deleteSite10DeleteSite6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event13adminEditUser13AdminEditUser6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event14changePassword14ChangePassword6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event12deleteDevice12DeleteDevice6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event10deleteRole10DeleteRole6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event10deleteUser10DeleteUser6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event10editDevice10EditDevice6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event5login5Login6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event8register8Register6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event11adminLogout11AdminLogout6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event15adminEditClient15AdminEditClient6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event9importMdb9ImportMdb6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event12deleteClient12DeleteClient6ParamsS4vibe4core4task4TaskmZvTDFS3vcm3bll5event18managerIncludeUser18ManagerIncludeUser6ParamsS4vibe4core
/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?
Mar 03 2017