Are messages thread safe?

Hi,

Currently performed a test with a couple of users on the server.

We experienced one crash, namely: fatal error - concurrent map writes.

From what i could tell from the log file the error came from a message received by a user. In tha action message i do write to a map.

I do write to the same map from both the main loop in a messages. Is this not ok?

So my question is - is messages recieved thread safe? or are they handled in a go routine?

Thanks in advance

Edit - pasting in stack strace

 fatal error: concurrent map writes
backend     | 
backend     | goroutine 292 [running]:
backend     | kdatstudios/halmgaard/src/world.(*EntityRegistry).Add(0xc00052e008, 0xc061d9f4a0)
backend     | 	kdatstudios/halmgaard/src/world/entity_registry.go:16 +0x56
backend     | kdatstudios/halmgaard/src/subsriber.(*entityRegistrySubscriber).EntityAdded(0xc04d0e13d0, {0x7fd2c6551d90, 0xc06a1833e0})
backend     | 	kdatstudios/halmgaard/src/subsriber/entity_registry_event_subrscriber.go:48 +0xc5
backend     | github.com/gookit/event.ListenerFunc.Handle(0xc04d0e13e0, {0x7fd2c6551d90, 0xc06a1833e0})
backend     | 	github.com/gookit/event@v1.0.6/listener.go:18 +0x3d
backend     | github.com/gookit/event.(*Manager).FireEvent(0xc000042480, {0x7fd2c6551d90, 0xc06a1833e0})
backend     | 	github.com/gookit/event@v1.0.6/manager.go:244 +0x6c3
backend     | github.com/gookit/event.(*Manager).Fire(0xc000042480, {0x7fd2c640b646, 0xc}, 0xc06a1833b0)
backend     | 	github.com/gookit/event@v1.0.6/manager.go:184 +0x3b7
backend     | github.com/gookit/event.Fire({0x7fd2c640b646, 0xc}, 0xc06a1833b0)
backend     | 	github.com/gookit/event@v1.0.6/global.go:45 +0x7d
backend     | kdatstudios/halmgaard/src/events.FireEntityAddedEvent(0xc061d9f4a0)
backend     | 	kdatstudios/halmgaard/src/events/event.go:22 +0xa7
backend     | kdatstudios/halmgaard/src/world.(*World).AddEntity(0xc0001ba1e0, 0xc061d9f4a0, {0x248, 0x3d, 0x0})
backend     | 	kdatstudios/halmgaard/src/world/world.go:63 +0x1a5
backend     | kdatstudios/halmgaard/src/system.(*SpawnSystem).Process(0xc0645f0320, {0x7fd2c6551880, 0xc0015001c8}, 0x1e)
backend     | 	kdatstudios/halmgaard/src/system/spawn_system.go:106 +0x845
backend     | kdatstudios/halmgaard/src/core.(*defaultEngine).Tick(0xc0003f8d00, 0x1e)
backend     | 	kdatstudios/halmgaard/src/core/default_engine.go:27 +0x108
backend     | kdatstudios/halmgaard.(*Container).MatchLoop(0xc0005fc3c0, {0x2b57598, 0xc06428d740}, {0x2b5d548, 0xc0007ba560}, 0xc0004ba000, {0x2b6f220, 0xc000166c80}, {0x2b58328, 0xc0006186c0}, ...)
backend     | 	kdatstudios/halmgaard/main.go:214 +0x524
backend     | github.com/heroiclabs/nakama/v3/server.(*RuntimeGoMatchCore).MatchLoop(0xc0006186c0, 0x0, {0x7fd2c6476ee0, 0xc0001204b0}, 0xc0001ae960)
backend     | 	github.com/heroiclabs/nakama/v3/server/runtime_go_match_core.go:184 +0x2f0
backend     | github.com/heroiclabs/nakama/v3/server.loop(0xc000167e00)
backend     | 	github.com/heroiclabs/nakama/v3/server/match_handler.go:288 +0xfa
backend     | github.com/heroiclabs/nakama/v3/server.NewMatchHandler.func2()
backend     | 	github.com/heroiclabs/nakama/v3/server/match_handler.go:193 +0x2fa
backend     | created by github.com/heroiclabs/nakama/v3/server.NewMatchHandler
backend     | 	github.com/heroiclabs/nakama/v3/server/match_handler.go:179 +0xb65

Every trace after this line
kdatstudios/halmgaard/src/core/default_engine.go:27 +0x108
im not using any concurency. So im trying to understand where it comes from.

/G

Hello @gruset, each match runs in a goroutine, is the map only accessed within the match itself?

yes, and we only have one match on the server (mmorpg).

So im wondering if the handler that handles the messages is handles async?

The messages are received by the gouroutine handling the socket connection, but they are put in a buffer that is then flushed to the match loop when the next tick happens, and the match loop is executed sequentially at every tick. If the map in question is only accessed from within your match loop I don’t see how this could happen.

The logs are unfortunately not very useful since they related to custom code, if you can please create a reproducible example of this and share the code with us.

Im not even sure i can reproduce it. I will have to give it a try and see when and where it happends. Thanks anyways for ur answer mate!