Your approach is mostly sound. You don’t need to ever close a GeomTriangles, though. That’s just for primitives with a variable number of vertices, such as a GeomTristrips.
As for the GeomVertexWriters, they aren’t intended to be cached, but rather recreated on every update. Otherwise, your game will hang under the multi-threaded render pipeline, since the GeomVertexWriters “lock” access to the geometry while they are operating.
If you run into performance issues, a more efficient way to do geometry updates is via memoryview, this is described in the manual.