Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pet Daemon #1413

Closed
wants to merge 23 commits into from
Closed

Pet Daemon #1413

wants to merge 23 commits into from

Conversation

kriskowal
Copy link
Member

@kriskowal kriskowal commented Dec 20, 2022

Individually reviewable commits.

This change will introduce pet-named workers, storage, and values to the Endo Daemon and expose them with its CLI. With this change, the following workflows become possible:

Ephemeral evaluation in an isolated worker:

$ endo spawn worker
$ endo eval worker 10
10

Persisted evaluation from a worker, using a pet name and a derivation path.

$ endo eval worker 10 --name ten
10
$ endo restart
$ end show ten
10

Evaluation with endowments:

$ endo eval worker 'ten + ten' ten --name twenty
20
$ endo restart
$ endo show twenty
20

Storage:

$ endo store <(echo hi) --name hi
$ endo cat hi
hi

Storage of archive:

$ endo archive foo.js --name foo
$ endo cat foo | tar t
... foo.js

These are a preamble to composite commands like endo install, which would store, spawn, and eval (or rather, importBundle), and subsequent work to reveal pet named capabilities to workers on-demand at the user’s discretion. endo follow [name] is also an obvious next step, for following a pet-named async iterator.

@dckc
Copy link
Contributor

dckc commented Dec 21, 2022

How do I run endo spawn worker? I don't see a bin/endo. I tried yarn endo without luck. halp?

p.s. found it: packages/cli

@dckc
Copy link
Contributor

dckc commented Dec 21, 2022

more struggles:

~/projects/endo/packages/cli$ ./bin/endo store ./test/counter.js --name mkc
(TypeError#1)
TypeError#1: cmd.options is not a function

  at Command.<anonymous> (packages/cli/src/endo.js:217:28)
  at main (packages/cli/src/endo.js:314:19)
  at async packages/cli/bin/endo.cjs:4:3

fwiw, ./test/counter.js contains:

const makeCounter = () => {
  let value = 0;
  return {
    incr: () => (value += 1),
    decr: () => (value -= 1),
  };
};

makeCounter;

@dckc
Copy link
Contributor

dckc commented Dec 22, 2022

I tried to endo store without first doing an endo start. The resulting diagnostic was not maximally informative:

Error#1: connect ENOENT /run/user/1000/endo/captp0.sock

@dckc
Copy link
Contributor

dckc commented Dec 22, 2022

Is there a missing mkdir() somewhere?

I kept getting EACCES: permission denied /run/user/1000/endo/captp0.sock. Even with export XDG_RUNTIME_DIR=/tmp/r1, I got EACCES: permission denied /tmp/r1/endo/captp0.sock.

mkdir /tmp/r1/endo seems to make it happy.

@dckc
Copy link
Contributor

dckc commented Dec 22, 2022

does this thing use sloppy eval? shouldn't this give ReferenceError?

$ ./bin/endo eval w1 'atob' mkc
undefined

Copy link
Contributor

@dckc dckc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

notes so far...

@@ -1,9 +1,16 @@
import type { FarRef } from '@endo/far';

type Pet = any;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm... would unknown work? Or should Pet be a type parameter?


const { quote: q } = assert;

const validNamePattern = /^[a-z][a-z0-9]*$/;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these used as filenames? that implies a length limit, no?

stream() {
const storageDirectoryPath = path.join(locator.statePath, 'store-sha512');
const storagePath = path.join(storageDirectoryPath, sha512);
const nodeReadStream = fs.createReadStream(storagePath);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ambient authority? hm.

// but also because we won't know the name we will use until we've
// completed the hash.
const digester = crypto.createHash('sha512');
const storageUuid = crypto.randomUUID();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ambient authority?

Comment on lines 145 to 161
await fs.promises.mkdir(workerCachePath, { recursive: true });
await fs.promises.mkdir(workerStatePath, { recursive: true });
await fs.promises.mkdir(workerEphemeralStatePath, { recursive: true });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the order of these matter? optimize turns with Promise.all([])?

* @param {Array<string>} petNames
* @param {string} resultName
*/
async evaluate(source, codeNames, petNames, resultName) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

endo doesn't follow the agoric-sdk arrow function style?

const output = fs.openSync(logPath, 'w');
const child = popen.fork(endoWorkerPath, [uuid, workerCachePath], {
stdio: ['ignore', output, output, 'pipe', 'ipc'],
const provideReadableSha512 = (locator, sha512) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as we discussed, seems to make a new one always. should be called makeReadableSha512

'Assigns a pet name to the result for future reference',
)
.action(async (storablePath, cmd) => {
const { name } = cmd.options();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const { name } = cmd.options();
const { name } = cmd.opts();

sha512() {
return sha512;
},
stream() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a text() method a la:

index c8b964637..42e6bbd71 100644
--- a/packages/daemon/src/daemon.js
+++ b/packages/daemon/src/daemon.js
@@ -47,13 +47,21 @@ const sinkError = error => {
  * @param {string} sha512
  */
 const provideReadableSha512 = (locator, sha512) => {
+  const getPath = () => {
+    const storageDirectoryPath = path.join(locator.statePath, 'store-sha512');
+    const storagePath = path.join(storageDirectoryPath, sha512);
+    return storagePath;
+  };
+
   return Far(`Readable file with SHA-512 ${sha512.slice(0, 8)}...`, {
     sha512() {
       return sha512;
     },
+    text() {
+      return fs.promises.readFile(getPath(), 'utf8');
+    },
     stream() {
-      const storageDirectoryPath = path.join(locator.statePath, 'store-sha512');
-      const storagePath = path.join(storageDirectoryPath, sha512);
+      const storagePath = getPath();
       const nodeReadStream = fs.createReadStream(storagePath);
       const reader = makeNodeReader(nodeReadStream);
       return makeReaderRef(reader);
~

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that allowed me to do:

$ ./bin/endo eval w1 'E(mkc).text()' mkc
const makeCounter = () => {
  let value = 0;
  return {
    incr: () => (value += 1),
    decr: () => (value -= 1),
  };
};

makeCounter;

but this hangs:

./bin/endo eval w1 'E(mkc).text().then(eval)' mkc

I couldn't find a worker log. (I did find a worker .pid file.)

@dckc
Copy link
Contributor

dckc commented Dec 22, 2022

Is it as-designed that objects-as-closures don't keep their internal state across restarts?

This surprised me:

endo/packages/cli$ ./bin/endo eval w1 'E(c1).incr()' c1 --name five
5
endo/packages/cli$ ./bin/endo restart
endo/packages/cli$ ./bin/endo eval w1 'five' five
1

That was after...

endo/packages/cli$ ./bin/endo store ./test/counter.js --name csrc
endo/packages/cli$ ./bin/endo eval w1 'E(csrc).text().then(eval)' csrc --name mcc
Object [Alleged: makeCounter] {}
endo/packages/cli$ ./bin/endo eval w1 'E(mcc).make()' mcc
Object [Alleged: Counter] {}
endo/packages/cli$ ./bin/endo eval w1 'E(mcc).make()' mcc --name c1
Object [Alleged: Counter] {}
endo/packages/cli$ ./bin/endo eval w1 'E(c1).incr()' c1
1
endo/packages/cli$ ./bin/endo eval w1 'E(c1).incr()' c1
2
endo/packages/cli$ ./bin/endo eval w1 'E(c1).incr()' c1
3
endo/packages/cli$ ./bin/endo eval w1 'E(c1).incr()' c1
4

@kriskowal kriskowal force-pushed the kris-fix-xdg branch 4 times, most recently from 3b4673c to 50fef2f Compare December 29, 2022 06:53
@kriskowal kriskowal marked this pull request as draft June 19, 2023 23:06
@kriskowal kriskowal force-pushed the kris-pet-daemon branch 2 times, most recently from dea9f89 to 02d7399 Compare June 28, 2023 23:48
@kriskowal
Copy link
Member Author

All feedback captured in the endo branch. Thank you!

@kriskowal kriskowal closed this Aug 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants