winglang / wing

A programming language for the cloud ☁️ A unified programming model, combining infrastructure and runtime code into one language ⚡
https://winglang.io
Other
4.91k stars 194 forks source link

`cloud.Service` Cannot Stop Service That Runs Continuous Loop #6888

Open hasanaburayyan opened 1 month ago

hasanaburayyan commented 1 month ago

I tried this:

wing it

bring cloud;
bring util;

let bucket = new cloud.Bucket();
let counter = new cloud.Counter();

let s = new cloud.Service(inflight () => {
  while true {
    bucket.put("file{counter.inc()}.txt", "Hello, world!");
    util.sleep(10s);
  }

  return inflight () => {
    for file in bucket.list() {
      bucket.delete(file);
    }
  };
});

new cloud.Function(inflight () => {
  s.start();
}) as "start service";

new cloud.Function(inflight () => {
  s.stop();
}) as "stop service";

This happened:

Invoking the stop function does nothing. (this is because we expect the start inflight to return the stop closure, but in this case the stop closure is never returned

I expected this:

Service to be stopped and files to be deleted

Is there a workaround?

No response

Anything else?

The implementation of cloud.Service probably needs to be reworked. It probably makes sense to have a more robust API maybe a service needs to be able to communicated starting, running, stopping, stoped

Wing Version

No response

Node.js Version

No response

Platform(s)

No response

Community Notes

hasanaburayyan commented 1 month ago

I think the simplest solution for now is to change the return type of cloud.Service to return a run and stop handler, the run handler is called when start handler completes:

Rough Sketch

let s = new cloud.Service(inflight () => {
  // This is starting code
  // ....

  // Return a run and stop handler
  return {
    run: inflight() => {
      while true {
          bucket.put("file{counter.inc()}.txt", "Hello, world!");
          util.sleep(10s);
      }
    },
    stop: inflight () => {
      for file in bucket.list() {
        bucket.delete(file);
      }
    }
  }
});
Chriscbr commented 1 month ago

No strong opinions from me on the API design -- @hasanaburayyan I'm cool with trying any alternatives as you see fit

I'll throw one more API idea to throw into the mix (I'm not sure if the "ctx.onStart()" part would be necessary or not)

let s = new cloud.Service(inflight (ctx) => {
  ctx.onStop(() => {
    for file in bucket.list() {
      bucket.delete(file);
    }
  });

  // ctx.onStart(() => {
    while true {
      bucket.put("file{counter.inc()}.txt", "Hello, world!");
      util.sleep(10s);
    }
  // });
});
Chriscbr commented 1 month ago

If the issue is related to the onStart code blocking because we automatically await most inflight code in JS land, we could add some kind of "defer" utility function (related to https://github.com/winglang/wing/issues/116) to let users write work around it:

new cloud.Service(inflight () => {
  util.defer(() => {
    // code to run without the implicit "await"
  });

  return /* onStop code */;
});

(This would be an temporary substitute for the defer x dedicated syntax so we can avoid introducing Promise<T> types for now)