From 187167a45271ec02f0b9225afb729e926cb212c8 Mon Sep 17 00:00:00 2001 From: David Grove Date: Tue, 22 Mar 2022 15:49:30 -0400 Subject: [PATCH] make session a query parameter (#282) --- .travis.yml | 13 ++++----- core/internal/runtime/commands.go | 16 ++++++----- core/internal/runtime/routes-docs.go | 16 ++++------- docs/api/swagger.json | 18 ++++++++----- docs/api/swagger.yaml | 23 ++++++++++------ examples/actors-dp-js/tester.js | 4 +-- examples/actors-ykt/ykt-client.js | 10 +++---- examples/unit-tests/actor-loop.js | 2 +- examples/unit-tests/test-harness.js | 18 ++++++------- .../kar/liberty/ActorRuntimeResource.java | 18 ++++++++----- .../research/kar/quarkus/ActorEndpoints.java | 26 ++++++++++++------ sdk-js/index.js | 27 ++++++++----------- sdk-python/kar/api.py | 4 +-- 13 files changed, 106 insertions(+), 89 deletions(-) diff --git a/.travis.yml b/.travis.yml index 51829cf9..47735406 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,12 +58,13 @@ jobs: script: - ./scripts/docker-compose-start.sh || travis_terminate 1 - make docker-run-containerized-python-examples - - name: local-released - script: - - ./scripts/docker-compose-start.sh || travis_terminate 1 - - make cli || travis_terminate 1 - - ./ci/testJSLocal.sh - - ./ci/testJavaLocal.sh +# Disabled due to backwards incompatible sidecar API changes +# - name: local-released +# script: +# - ./scripts/docker-compose-start.sh || travis_terminate 1 +# - make cli || travis_terminate 1 +# - ./ci/testJSLocal.sh +# - ./ci/testJavaLocal.sh - name: in-cluster script: - ./scripts/kind-start.sh || travis_terminate 1 diff --git a/core/internal/runtime/commands.go b/core/internal/runtime/commands.go index 6c43b519..eb7df7e3 100644 --- a/core/internal/runtime/commands.go +++ b/core/internal/runtime/commands.go @@ -308,6 +308,7 @@ func handlerService(ctx context.Context, target rpc.Service, value []byte) ([]by func handlerActor(ctx context.Context, target rpc.Session, instance *rpc.SessionInstance, requestID string, value []byte) (*rpc.Destination, []byte, error) { actor := Actor{Type: target.Name, ID: target.ID} + session := target.Flow + ":" + requestID var reply []byte = nil var err error = nil var msg map[string]string @@ -336,7 +337,7 @@ func handlerActor(ctx context.Context, target rpc.Session, instance *rpc.Session var dest *rpc.Destination = nil if !instance.Activated { - reply, err = activate(ctx, actor, msg["command"] == "call", msg["path"]) + reply, err = activate(ctx, actor, session, msg) if reply != nil { // activate returned an application-level error, do not retry err = nil @@ -348,7 +349,7 @@ func handlerActor(ctx context.Context, target rpc.Session, instance *rpc.Session if instance.Activated { // invoke actor method metricLabel := actor.Type + ":" + msg["path"] // compute metric label before we augment the path with id+flow - msg["path"] = actorRuntimeRoutePrefix + actor.Type + "/" + actor.ID + "/" + target.Flow + ":" + requestID + msg["path"] + msg["path"] = actorRuntimeRoutePrefix + actor.Type + "/" + actor.ID + msg["path"] + "?session=" + session msg["content-type"] = "application/kar+json" msg["method"] = "POST" @@ -527,8 +528,9 @@ func getActorInformation(ctx context.Context, msg map[string]string) ([]byte, er } // activate an actor -func activate(ctx context.Context, actor Actor, isCall bool, causingMethod string) ([]byte, error) { - reply, err := invoke(ctx, "GET", map[string]string{"path": actorRuntimeRoutePrefix + actor.Type + "/" + actor.ID}, actor.Type+":activate") +func activate(ctx context.Context, actor Actor, session string, causingMsg map[string]string) ([]byte, error) { + activatePath := actorRuntimeRoutePrefix + actor.Type + "/" + actor.ID + "?session=" + session + reply, err := invoke(ctx, "GET", map[string]string{"path": activatePath}, actor.Type+":activate") if err != nil { if err != ctx.Err() { logger.Debug("activate failed to invoke %s: %v", actorRuntimeRoutePrefix+actor.Type+"/"+actor.ID, err) @@ -536,11 +538,11 @@ func activate(ctx context.Context, actor Actor, isCall bool, causingMethod strin return nil, err } if reply.StatusCode >= http.StatusBadRequest { - if isCall { - logger.Debug("activate %v returned status %v with body %s, aborting call %s", actor, reply.StatusCode, reply.Payload, causingMethod) + if causingMsg["command"] == "call" { + logger.Debug("activate %v returned status %v with body %s, aborting call %s", actor, reply.StatusCode, reply.Payload, causingMsg["path"]) } else { // Log at error level becasue there is no one waiting on the method reponse to notice the failure. - logger.Error("activate %v returned status %v with body %s, aborting tell %s", actor, reply.StatusCode, reply.Payload, causingMethod) + logger.Error("activate %v returned status %v with body %s, aborting tell %s", actor, reply.StatusCode, reply.Payload, causingMsg["path"]) } return json.Marshal(reply) } diff --git a/core/internal/runtime/routes-docs.go b/core/internal/runtime/routes-docs.go index d233850c..86a44212 100644 --- a/core/internal/runtime/routes-docs.go +++ b/core/internal/runtime/routes-docs.go @@ -132,7 +132,7 @@ func dummy1() {} // func dummy2() {} -// swagger:route POST /impl/v1/actor/{actorType}/{actorId}/{session}/{methodName} actor-runtime idImplActorPost +// swagger:route POST /impl/v1/actor/{actorType}/{actorId}/{methodName} actor-runtime idImplActorPost // // actor invocation // @@ -288,19 +288,13 @@ type methodParam struct { } // swagger:parameters idActorCall +// swagger:parameters idImplActorGet +// swagger:parameters idImplActorPost type sessionParam struct { - // Optionally specific the session to use when performing the call. Enables re-entrancy for nested actor calls. + // The session is an opaque string used by the KAR runtime to enable reentrancy + // for nested actor calls and to track caller-callee relationships for failure recovery // in:query // required:false - // swagger:strfmt uuid - Session string `json:"session"` -} - -// swagger:parameters idImplActorPost -type sessionPathParam struct { - // The session to use for the actor method invocation. - // in:path - // swagger:strfmt uuid Session string `json:"session"` } diff --git a/docs/api/swagger.json b/docs/api/swagger.json index da91a882..87bf2853 100644 --- a/docs/api/swagger.json +++ b/docs/api/swagger.json @@ -71,6 +71,13 @@ "name": "actorId", "in": "path", "required": true + }, + { + "type": "string", + "x-go-name": "Session", + "description": "The session is an opaque string used by the KAR runtime to enable reentrancy\nfor nested actor calls and to track caller-callee relationships for failure recovery", + "name": "session", + "in": "query" } ], "responses": { @@ -126,7 +133,7 @@ } } }, - "/impl/v1/actor/{actorType}/{actorId}/{session}/{methodName}": { + "/impl/v1/actor/{actorType}/{actorId}/{methodName}": { "post": { "description": "### Invoke an actor method of the specified actor instance\n\nInvokes the actor method on the actor instance within the session specified in the path.\nThe body of the request will contain the actual paramters on which to invoke the method.", "consumes": [ @@ -171,12 +178,10 @@ }, { "type": "string", - "format": "uuid", "x-go-name": "Session", - "description": "The session to use for the actor method invocation.", + "description": "The session is an opaque string used by the KAR runtime to enable reentrancy\nfor nested actor calls and to track caller-callee relationships for failure recovery", "name": "session", - "in": "path", - "required": true + "in": "query" }, { "example": "[3, 'hello', { msg: 'Greetings' }]", @@ -285,9 +290,8 @@ }, { "type": "string", - "format": "uuid", "x-go-name": "Session", - "description": "Optionally specific the session to use when performing the call. Enables re-entrancy for nested actor calls.", + "description": "The session is an opaque string used by the KAR runtime to enable reentrancy\nfor nested actor calls and to track caller-callee relationships for failure recovery", "name": "session", "in": "query" }, diff --git a/docs/api/swagger.yaml b/docs/api/swagger.yaml index 70a02889..69270c35 100644 --- a/docs/api/swagger.yaml +++ b/docs/api/swagger.yaml @@ -316,6 +316,13 @@ paths: required: true type: string x-go-name: ActorID + - description: |- + The session is an opaque string used by the KAR runtime to enable reentrancy + for nested actor calls and to track caller-callee relationships for failure recovery + in: query + name: session + type: string + x-go-name: Session responses: "200": $ref: '#/responses/response200' @@ -328,7 +335,7 @@ paths: summary: actor allocation tags: - actor-runtime - /impl/v1/actor/{actorType}/{actorId}/{session}/{methodName}: + /impl/v1/actor/{actorType}/{actorId}/{methodName}: post: consumes: - application/kar+json @@ -358,11 +365,11 @@ paths: required: true type: string x-go-name: MethodName - - description: The session to use for the actor method invocation. - format: uuid - in: path + - description: |- + The session is an opaque string used by the KAR runtime to enable reentrancy + for nested actor calls and to track caller-callee relationships for failure recovery + in: query name: session - required: true type: string x-go-name: Session - description: A possibly empty array containing the arguments with which to @@ -454,9 +461,9 @@ paths: required: true type: string x-go-name: MethodName - - description: Optionally specific the session to use when performing the call. Enables - re-entrancy for nested actor calls. - format: uuid + - description: |- + The session is an opaque string used by the KAR runtime to enable reentrancy + for nested actor calls and to track caller-callee relationships for failure recovery in: query name: session type: string diff --git a/examples/actors-dp-js/tester.js b/examples/actors-dp-js/tester.js index 3c97ddcc..8d77478c 100644 --- a/examples/actors-dp-js/tester.js +++ b/examples/actors-dp-js/tester.js @@ -39,11 +39,11 @@ async function main () { const cafe = actor.proxy('Cafe', 'Cafe+de+Flore') console.log('Serving a meal:') - const table = await actor.call(cafe, 'seatTable', 20, 5) + const table = await actor.rootCall(cafe, 'seatTable', 20, 5) let occupancy = 1 while (occupancy > 0 & !failure) { - occupancy = await actor.call(cafe, 'occupancy', table) + occupancy = await actor.rootCall(cafe, 'occupancy', table) console.log(`Table occupancy is ${occupancy}`) await sleep(2000) countdown = countdown - 1 diff --git a/examples/actors-ykt/ykt-client.js b/examples/actors-ykt/ykt-client.js index 907d6cee..a9a179ff 100644 --- a/examples/actors-ykt/ykt-client.js +++ b/examples/actors-ykt/ykt-client.js @@ -51,7 +51,7 @@ function prettyPrintHistogram (header, bucketSizeInMS, histogram) { async function summaryReport (division) { const summary = { onboarding: 0, home: 0, commuting: 0, working: 0, meeting: 0, coffee: 0, lunch: 0 } for (const site of division) { - const sr = await actor.call(site.proxy, 'siteReport') + const sr = await actor.rootCall(site.proxy, 'siteReport') summary.onboarding += sr.onboarding || 0 summary.home += sr.home || 0 summary.commuting += sr.commuting || 0 @@ -79,21 +79,21 @@ async function main () { } for (const site of researchDivision) { - await actor.call(site.proxy, 'resetDelayStats') + await actor.rootCall(site.proxy, 'resetDelayStats') await actor.reminders.schedule(site.proxy, 'siteReport', { id: 'clientSiteReport', targetTime: new Date(Date.now() + 1000), period: '1s' }) - await actor.call(ibm, 'hire', Object.assign({ site: site.proxy.kar.id }, site.params)) + await actor.rootCall(ibm, 'hire', Object.assign({ site: site.proxy.kar.id }, site.params)) } while (true) { await sleep(5000) - const employees = await actor.call(ibm, 'count') + const employees = await actor.rootCall(ibm, 'count') console.log(`Num employees is ${employees}`) if (employees === 0) { const summary = { reminderDelays: [], tellLatencies: [] } let bucketSizeInMS for (const site of researchDivision) { console.log(`Valiadating ${site.proxy.kar.id}`) - const sr = await actor.call(site.proxy, 'siteReport') + const sr = await actor.rootCall(site.proxy, 'siteReport') if (sr.siteEmployees !== 0) { console.log(`FAILURE: ${sr.siteEmployees} stranded employees at ${site.proxy.kar.id}`) failure = true diff --git a/examples/unit-tests/actor-loop.js b/examples/unit-tests/actor-loop.js index 877172d3..bc558d13 100644 --- a/examples/unit-tests/actor-loop.js +++ b/examples/unit-tests/actor-loop.js @@ -20,7 +20,7 @@ async function main () { let x = 0 const a = actor.proxy('Foo', 'myInstance') for (let i = 0; i < 5000; i++) { - x = await actor.call(a, 'incr', x) + x = await actor.rootCall(a, 'incr', x) console.log(i, '->', x) } console.log('=>', x) diff --git a/examples/unit-tests/test-harness.js b/examples/unit-tests/test-harness.js index 9db90c8a..385e80ec 100644 --- a/examples/unit-tests/test-harness.js +++ b/examples/unit-tests/test-harness.js @@ -194,7 +194,7 @@ async function actorTests () { // external synchronous invocation of an actor method for (let i = 0; i < 25; i++) { - const x = await actor.call(actor.proxy('Foo', 'anotherInstance'), 'incrQuiet', i) + const x = await actor.rootCall(actor.proxy('Foo', 'anotherInstance'), 'incrQuiet', i) if (x !== i + 1) { console.log(`Failed! incr(${i}) returned ${x}`) failure = true @@ -202,7 +202,7 @@ async function actorTests () { } // synchronous invocation via the actor - const v6 = await actor.call(a, 'incr', 42) + const v6 = await actor.rootCall(a, 'incr', 42) if (v6 !== 43) { console.log(`Failed: unexpected result from incr ${v6}`) failure = true @@ -216,7 +216,7 @@ async function actorTests () { } // getter - const v7 = await actor.call(a, 'field') + const v7 = await actor.rootCall(a, 'field') if (v7 !== 42) { console.log(`Failed: getter of 'field' returned ${v7}`) failure = true @@ -225,7 +225,7 @@ async function actorTests () { console.log('Testing actor invocation error handling') // error in synchronous invocation try { - console.log(await actor.call(a, 'fail', 'error message 123')) + console.log(await actor.rootCall(a, 'fail', 'error message 123')) console.log('Failed to raise expected error') failure = true } catch (err) { @@ -234,7 +234,7 @@ async function actorTests () { // undefined method try { - console.log(await actor.call(a, 'missing', 'error message 123')) + console.log(await actor.rootCall(a, 'missing', 'error message 123')) console.log('Failed. No error raised invoking missing method') failure = true } catch (err) { @@ -242,7 +242,7 @@ async function actorTests () { } // reentrancy - const v9 = await actor.call(a, 'reenter', 42) + const v9 = await actor.rootCall(a, 'reenter', 42) if (v9 !== 43) { console.log(`Failed: unexpected result from reenter ${v9}`) failure = true @@ -266,7 +266,7 @@ async function pubSubTests () { await events.createTopic(topic) - const v1 = await actor.call(a, 'pubsub', topic) + const v1 = await actor.rootCall(a, 'pubsub', topic) if (v1 !== 'OK') { console.log('Failed: pubsub') failure = true @@ -274,7 +274,7 @@ async function pubSubTests () { let i for (i = 30; i > 0; i--) { // poll - const v2 = await actor.call(a, 'check', topic) + const v2 = await actor.rootCall(a, 'check', topic) if (v2 === true) break await new Promise(resolve => setTimeout(resolve, 500)) // wait } @@ -300,7 +300,7 @@ async function testTermination (failure) { } async function main () { - var failure = false + let failure = false console.log('*** Service Tests ***') failure |= await serviceTests() diff --git a/sdk-java/kar-runtime-liberty/src/main/java/com/ibm/research/kar/liberty/ActorRuntimeResource.java b/sdk-java/kar-runtime-liberty/src/main/java/com/ibm/research/kar/liberty/ActorRuntimeResource.java index 65b7314b..4b54e92c 100644 --- a/sdk-java/kar-runtime-liberty/src/main/java/com/ibm/research/kar/liberty/ActorRuntimeResource.java +++ b/sdk-java/kar-runtime-liberty/src/main/java/com/ibm/research/kar/liberty/ActorRuntimeResource.java @@ -33,6 +33,7 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; @@ -62,7 +63,7 @@ public class ActorRuntimeResource implements KarHttpConstants { @GET @Path("{type}/{id}") @Produces(MediaType.TEXT_PLAIN) - public Response getActor(@PathParam("type") String type, @PathParam("id") String id) { + public Response getActor(@PathParam("type") String type, @PathParam("id") String id, @QueryParam("session") String session) { ActorInstance actorInstance = ActorManager.getInstanceIfPresent(type, id); if (actorInstance != null) { return Response.ok().build(); @@ -82,9 +83,12 @@ public Response getActor(@PathParam("type") String type, @PathParam("id") String MethodHandle activate = actorType.getActivateMethod(); if (activate != null) { try { - activate.invoke(actorInstance); + actorInstance.setSession(session); + activate.invokeWithArguments(actorInstance); } catch (Throwable t) { return Response.status(BAD_REQUEST).type(TEXT_PLAIN).entity(t.toString()).build(); + } finally { + actorInstance.setSession(null); } } @@ -113,7 +117,7 @@ public Response deleteActor(@PathParam("type") String type, @PathParam("id") Str MethodHandle deactivateMethod = actorType.getDeactivateMethod(); if (deactivateMethod != null) { try { - deactivateMethod.invoke(actorInstance); + deactivateMethod.invokeWithArguments(actorInstance); } catch (Throwable t) { return Response.status(BAD_REQUEST).type(TEXT_PLAIN).entity(t.toString()).build(); } @@ -137,16 +141,16 @@ public Response checkActorType(@PathParam("type") String type) { * * @param type The type of the actor * @param id The id of the target instancr - * @param sessionid The session in which the method is being invoked + * @param session The session in which the method is being invoked * @param path The method to invoke * @param args The arguments to the method * @return a Response containing the result of the method invocation */ @POST - @Path("{type}/{id}/{sessionid}/{path}") + @Path("{type}/{id}/{path}") @Consumes(Kar.KAR_ACTOR_JSON) @Produces(Kar.KAR_ACTOR_JSON) - public Response invokeActorMethod(@PathParam("type") String type, @PathParam("id") String id, @PathParam("sessionid") String sessionid, @PathParam("path") String path, JsonArray args) { + public Response invokeActorMethod(@PathParam("type") String type, @PathParam("id") String id, @QueryParam("session") String session, @PathParam("path") String path, JsonArray args) { ActorInstance actorObj = ActorManager.getInstanceIfPresent(type, id); if (actorObj == null) { return Response.status(NOT_FOUND).type(TEXT_PLAIN).entity("Actor instance not found: " + type + "[" + id +"]").build(); @@ -167,7 +171,7 @@ public Response invokeActorMethod(@PathParam("type") String type, @PathParam("id String priorSession = actorObj.getSession(); try { - actorObj.setSession(sessionid); + actorObj.setSession(session); Object result = actorMethod.invokeWithArguments(actuals); if (result == null || actorMethod.type().returnType().equals(Void.TYPE)) { return Response.status(NO_CONTENT).build(); diff --git a/sdk-java/kar-runtime-quarkus/src/main/java/com/ibm/research/kar/quarkus/ActorEndpoints.java b/sdk-java/kar-runtime-quarkus/src/main/java/com/ibm/research/kar/quarkus/ActorEndpoints.java index b5a2fcc1..359cfaa1 100644 --- a/sdk-java/kar-runtime-quarkus/src/main/java/com/ibm/research/kar/quarkus/ActorEndpoints.java +++ b/sdk-java/kar-runtime-quarkus/src/main/java/com/ibm/research/kar/quarkus/ActorEndpoints.java @@ -43,6 +43,8 @@ import com.ibm.research.kar.runtime.ActorType; import com.ibm.research.kar.runtime.KarHttpConstants; +import org.jboss.resteasy.reactive.RestQuery; + import io.smallrye.mutiny.Uni; @Path("/kar/impl/v1/actor") @@ -63,7 +65,7 @@ public class ActorEndpoints implements KarHttpConstants { @GET @Path("/{type}/{id}") @Produces(MediaType.TEXT_PLAIN) - public Uni getActor(String type, String id) { + public Uni getActor(String type, String id, @RestQuery String session) { ActorInstance actorInstance = ActorManager.getInstanceIfPresent(type, id); if (actorInstance != null) { return Uni.createFrom().item(Response.ok().build()); @@ -86,11 +88,19 @@ public Uni getActor(String type, String id) { MethodHandle activate = actorType.getActivateMethod(); if (activate != null) { try { - Object result = activate.invoke(actorInstance); + actorInstance.setSession(session); + final ActorInstance capturedActorInstance = actorInstance; + Object result = activate.invokeWithArguments(actorInstance); if (result instanceof Uni) { - return ((Uni)result).chain(() -> Uni.createFrom().item(success)); + return ((Uni)result).chain(res -> { + capturedActorInstance.setSession(null); + return Uni.createFrom().item(success); + }); + } else { + actorInstance.setSession(null); } } catch (Throwable t) { + actorInstance.setSession(null); Response failure = Response.status(BAD_REQUEST).type(TEXT_PLAIN).entity(t.toString()).build(); return Uni.createFrom().item(failure); } @@ -122,7 +132,7 @@ public Uni deleteActor(String type, String id) { MethodHandle deactivateMethod = actorType.getDeactivateMethod(); if (deactivateMethod != null) { try { - Object result = deactivateMethod.invoke(actorInstance); + Object result = deactivateMethod.invokeWithArguments(actorInstance); if (result instanceof Uni) { return ((Uni)result).chain(() -> { ActorManager.removeInstanceIfPresent(type, id); @@ -151,16 +161,16 @@ public Response checkActorType(String type) { * * @param type The type of the actor * @param id The id of the target instancr - * @param sessionid The session in which the method is being invoked + * @param session The session in which the method is being invoked * @param path The method to invoke * @param args The arguments to the method * @return a Uni representing the result of the method invocation */ @POST - @Path("/{type}/{id}/{sessionid}/{path}") + @Path("/{type}/{id}/{path}") @Consumes(KAR_ACTOR_JSON) @Produces(KAR_ACTOR_JSON) - public Uni invokeActorMethod(String type, String id, String sessionid, String path, JsonArray args) { + public Uni invokeActorMethod(String type, String id, @RestQuery String session, String path, JsonArray args) { ActorInstance actorObj = ActorManager.getInstanceIfPresent(type, id); if (actorObj == null) { Response resp = Response.status(NOT_FOUND).type(TEXT_PLAIN).entity("Actor instance not found: " + type + "[" + id +"]").build(); @@ -183,7 +193,7 @@ public Uni invokeActorMethod(String type, String id, String sessionid, String priorSession = actorObj.getSession(); try { - actorObj.setSession(sessionid); + actorObj.setSession(session); Object result = actorMethod.invokeWithArguments(actuals); if (result == null || actorMethod.type().returnType().equals(Void.TYPE)) { actorObj.setSession(priorSession); diff --git a/sdk-js/index.js b/sdk-js/index.js index b7079472..d1fb63b5 100644 --- a/sdk-js/index.js +++ b/sdk-js/index.js @@ -160,18 +160,10 @@ function actorCall (...args) { } function actorRootCall (...args) { - if (typeof args[1] === 'string') { - // call (callee:Actor, path:string, ...args:any[]):Promise; - const ta = args.shift() - const path = args.shift() - return postActor(`actor/${ta.kar.type}/${ta.kar.id}/call/${path}`, args, { 'Content-Type': 'application/kar+json' }) - } else { - // call (from:Actor, callee:Actor, path:string, ...args:any[]):Promise; - const sa = args.shift() - const ta = args.shift() - const path = args.shift() - return postActor(`actor/${ta.kar.type}/${ta.kar.id}/call/${path}?session=${sa.kar.session}`, args, { 'Content-Type': 'application/kar+json' }) - } + // call (callee:Actor, path:string, ...args:any[]):Promise; + const ta = args.shift() + const path = args.shift() + return postActor(`actor/${ta.kar.type}/${ta.kar.id}/call/${path}`, args, { 'Content-Type': 'application/kar+json' }) } function actorAsyncCall (...args) { @@ -314,12 +306,15 @@ function actorRuntime (actors) { table[req.params.type] = table[req.params.type] || {} const actor = new Actor(req.params.id) table[req.params.type][req.params.id] = actor - table[req.params.type][req.params.id].kar = { type: req.params.type, id: req.params.id } + table[req.params.type][req.params.id].kar = { type: req.params.type, id: req.params.id, session: req.query.session } }) // instantiate actor and add to index .then(_ => { // run optional activate callback if (typeof table[req.params.type][req.params.id].activate === 'function') return table[req.params.type][req.params.id].activate() }) - .then(_ => res.sendStatus(201)) // Created + .then(_ => { + table[req.params.type][req.params.id].kar.session = undefined + return res.sendStatus(201) // Created + }) .catch(next) }) @@ -340,7 +335,7 @@ function actorRuntime (actors) { }) // method invocation route - router.post('/kar/impl/v1/actor/:type/:id/:session/:method', (req, res, next) => { + router.post('/kar/impl/v1/actor/:type/:id/:method', (req, res, next) => { const Actor = actors[req.params.type] if (Actor == null) return res.status(404).type('text/plain').send(`no actor type ${req.params.type}`) const actor = (table[req.params.type] || {})[req.params.id] @@ -349,7 +344,7 @@ function actorRuntime (actors) { const priorSession = actor.kar.session return Promise.resolve() .then(_ => { - actor.kar.session = req.params.session + actor.kar.session = req.query.session if (typeof actor[req.params.method] === 'function') return actor[req.params.method](...req.body) return actor[req.params.method] }) // invoke method on actor diff --git a/sdk-python/kar/api.py b/sdk-python/kar/api.py index de598c08..8751af40 100644 --- a/sdk-python/kar/api.py +++ b/sdk-python/kar/api.py @@ -851,8 +851,8 @@ def delete(type: str, id: int): return PlainTextResponse(status_code=200, content="deleted") # Method to call actor methods. - @actor_server.post(f"{kar_url}" + "/{type}/{id}/{session}/{method}") - async def post(type: str, id: int, session: str, method: str, + @actor_server.post(f"{kar_url}" + "/{type}/{id}/{method}") + async def post(type: str, id: int, method: str, request: Request): # Check that the message has JSON type. if not request.headers['content-type'] in [