Open technicallyty opened 9 months ago
Hey @technicallyty, "continuation after FIN" happens when data or packets continue to be sent after a FIN has been issued. It's likely there is some half-closed connection occurring between the sockets. It's not something we've seen before. Is this something you are reproducing locally?
yeah, im just testing out RPC calls to a local nakama instance. fwiw, ive gotten rid of this error. but now the socket just... stops working after some time? i can just post my integration code here:
import {Client, Session, Socket} from "@heroiclabs/nakama-js";
import {ReadMonsterStatusResponse} from "./types.ts";
import {ApiRpc} from "@heroiclabs/nakama-js/dist/api.gen";
interface NakamaIdentifier {
DeviceID: string;
Session: Session;
}
class Nakama {
private client: Client;
private readonly useSSL: boolean;
private identifiers: Map<string, NakamaIdentifier>;
constructor() {
this.client = new Client("defaultkey", "localhost", "7350");
this.useSSL = false; // Initialize useSSL with a default value.
this.identifiers = new Map<string, NakamaIdentifier>;
}
async authenticate(userName: string) : Promise<any> {
const email: string = userName + "@gmail.com";
const pass: string = "FooBar1234567890!";
let session: Session = await this.client.authenticateEmail(
email,
pass,
true,
userName
);
let sock: Socket = this.client.createSocket(this.useSSL, false);
await sock.connect(session, true);
const payload: string = JSON.stringify({ persona_tag: userName});
await sock.rpc(
"nakama/claim-persona",
payload
).catch(e => {
console.error(e)
})
this.identifiers[userName] = {DeviceID: email, Session: session}
sock.disconnect(false);
}
async status(personaTag: string) : Promise<ReadMonsterStatusResponse> {
const payload: string = JSON.stringify({Owner: personaTag});
let response = await this.makeRPCCall(personaTag, payload, "read-monster")
return JSON.parse(response.payload!);
}
async recall(personaTag: string) : Promise<void> {
const payload: string = JSON.stringify({});
await this.makeRPCCall(personaTag, payload, "tx-recall-monster");
}
async adventure(personaTag: string, difficulty: string) : Promise<void> {
const payload: string = JSON.stringify({Difficulty: difficulty});
await this.makeRPCCall(personaTag, payload, "tx-adventure");
}
async nameMonster(personaTag: string, monsterName: string) : Promise<void> {
const payload: string = JSON.stringify({ Name: monsterName });
await this.makeRPCCall(personaTag, payload, "tx-name-monster");
}
async feedMonster(personaTag: string) : Promise<void> {
const payload: string = JSON.stringify({});
await this.makeRPCCall(personaTag, payload, "tx-feed-monster");
}
async claimMonster(personaTag: string) : Promise<void> {
const payload: string = JSON.stringify({});
await this.makeRPCCall(personaTag, payload, "tx-claim-monster");
}
async checkPersona(personaTag: string) : Promise<void> {
const payload: string = JSON.stringify({ persona_tag: personaTag});
await this.makeRPCCall(personaTag, payload,"nakama/show-persona")
}
async makeRPCCall(personaTag: string, payload: string, rpcName: string) : Promise<ApiRpc> {
let id: NakamaIdentifier = this.identifiers[personaTag];
let sock: Socket = this.client.createSocket(this.useSSL, false);
await sock.connect(id.Session, false).catch(e => {
console.error("ERROR CONNECTING TO SOCKET")
console.error(e);
});
let response = await sock.rpc(
rpcName,
payload,
)
console.debug(response.http_key)
console.debug(response.id)
console.debug(response.payload)
sock.disconnect(false);
return response;
}
}
export default Nakama; // Export the Nakama class itself.
I recommend making your RPCs from the client
object instead of the socket. Your pattern appears to be more of a request-response model and when you use the client
you won't need to setup and tear down the socket anymore -- that's just incurring unnecessary overhead and complexity.
ok i switched to RPC and thats fine. but now im using a socket to connect to a match and listen for things. and i randomly get that "continuation" error as described above. its still not clear why thats happening
cc @lugehorsam
@technicallyty could you share your connection open and close logic and how long your typical match is?
@technicallyty could you share your connection open and close logic and how long your typical match is?
the match is never intended to close, it should be alive as long as our nakama instance is running.
this.receiptChannel = this.client.createSocket(false, false);
this.receiptChannel.onmatchdata = result => {
console.log("received match data:")
console.log(result);
}
this.receiptChannel.ondisconnect = evt => {
console.log("disconnecting socket...");
console.log(evt);
}
this.receiptChannel.onerror = e => {
console.log("received error...")
console.log(e);
}
let sesh = await this.receiptChannel.connect(session, false);
let result = await this.client.listMatches(sesh);
let matchId = result.matches[0].match_id;
await this.receiptChannel.joinMatch(matchId);
As an aside, I would be careful about designing a system where matches open and run indefinitely without closing. Your server will OOM if you do that.
How long does your match typically run before you see this issue?
As an aside, I would be careful about designing a system where matches open and run indefinitely without closing. Your server will OOM if you do that.
How long does your match typically run before you see this issue?
Is there a reason why this is the case? Is there some sort of memory leak within the match runtime?
@smsunarto There is no memory leak in the server but if you have new matches created continuously and keep them alive without recycling them back into use with players you'll exhaust available memory.
This does not have anything to do with the intrinsic design of the multiplayer engine; you must consider how to utilize the finite resources of the hardware like with any server system.
How long does your match typically run before you see this issue?
usually 10-15 seconds
@smsunarto There is no memory leak in the server but if you have new matches created continuously and keep them alive without recycling them back into use with players you'll exhaust available memory.
This does not have anything to do with the intrinsic design of the multiplayer engine; you must consider how to utilize the finite resources of the hardware like with any server system.
Ah yes, to clarify, we only have 1 ongoing match at all times; we're basically treating it like a singleton match.
@technicallyty @smsunarto is this still an issue for you and if so, where are you running the server when you see the error? Is it local?
I'm using "@heroiclabs/nakama-js": "^2.6.1" to build a client in TypeScript. I use sockets to make calls to RPC's on the Nakama backend. For some reason, I randomly get these errors spit into my console:
my Go-based server is logging: (using github.com/heroiclabs/nakama-common v1.27.0)
It's really unclear why this is happening, and the error message doesn't provide much context to help me out.