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

feat(notifier): Add makeNotifierFromSubscriber #5737

Merged
merged 8 commits into from
Jul 14, 2022

Conversation

gibson042
Copy link
Member

@gibson042 gibson042 commented Jul 8, 2022

Fixes #5413

Description

Add makeNotifierFromSubscriber for lossy consumption of PublishKit subscriber objects via subscribeLatest (each getUpdateSince() call returns a unique already-settled promise for the latest result, each getUpdateSince(lastUpdateCount) call requests the next value [which under the covers constructs a new iterator] and returns a unique promise for it).

Also deprecates makeNotifierFromAsyncIterable.

This PR should land with a rebase rather than a squash; I have intentionally included the changes from #5695 along with an immediate reversion for posterity.

Security Considerations

None known.

Documentation Considerations

Agoric/documentation#684

Testing Considerations

More tests to come before merging.

harden(makeNotifierFromSubscriber);

/**
* Deprecated adaptor from async iterable to notifier.
Copy link
Member

Choose a reason for hiding this comment

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

https://www.typescriptlang.org/play#example/jsdoc-deprecated

Suggested change
* Deprecated adaptor from async iterable to notifier.
* @deprecated adaptor from async iterable to notifier.

Copy link
Member

Choose a reason for hiding this comment

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

Also please explain here why it's deprecated.

I have intentionally included the changes from #5695 along with an immediate reversion for posterity.

I request that those two commits be omitted (or this be landed as squash). For master it's noise. If there's something important to convey about how we got to this point then just write it in HEAD. If you want there to be some record of the other work done, it's already in the referenced PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm anticipating the attempt to come up again, and would like the prior record to outlive that dead branch.

Copy link
Member

Choose a reason for hiding this comment

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

The branch will be dead but #5695 will endure for anyone who wants to see it.

Non-blocking but I do think the PR suffices as a record and to the point of discover as to why this is the design, I don't think commit history suffices. If that's the goal is should be written into HEAD.

packages/notifier/test/test-notifier-adaptor.js Outdated Show resolved Hide resolved
packages/notifier/test/test-notifier-adaptor.js Outdated Show resolved Hide resolved

const sequence = [];
const firstP = notifier.getUpdateSince();
firstP.then(_ => sequence.push('resolve firstP'));
Copy link
Member

Choose a reason for hiding this comment

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

please address the floating promises on 250 and 252

Copy link
Member Author

Choose a reason for hiding this comment

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

Address in what way?

Copy link
Member

Choose a reason for hiding this comment

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

make the warnings go away :)

either by awaiting or putting void to indicate it need not be awaited. (the warning string explains another option is to .catch but that seems silly here)

packages/notifier/test/test-notifier-adaptor.js Outdated Show resolved Hide resolved
// /////////////////////////////// makeNotifierFromSubscriber /////////////////////////////////

/** @param {{conclusionMethod: 'finish' | 'fail', conclusionValue: any}} config */
const makeGeometricPublishKit = ({ conclusionMethod, conclusionValue }) => {
Copy link
Member

Choose a reason for hiding this comment

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

this sounds like it's making a PublicKit but it's returning something different.

Suggested change
const makeGeometricPublishKit = ({ conclusionMethod, conclusionValue }) => {
const makeGeometricPublishHelper = ({ conclusionMethod, conclusionValue }) => {

Looks like calls have the same arguments. Why parameterize?

Suggested change
const makeGeometricPublishKit = ({ conclusionMethod, conclusionValue }) => {
const makeGeometricPublishHelper = () => {

Also looks like all tests share this first line. Once this is in its own file, it would work well to put in a hook:

test.beforeEach(t => {
  Object.assign(t.context, makeGeometricPublishHelper());
}

Or even,

test.beforeEach(t => {
  Object.assign(t.context, makeGeometricPublishHelper());
  t.context.notifier = await makeNotifierFromSubscriber(t.context.subscriber);
}

Copy link
Member Author

@gibson042 gibson042 Jul 8, 2022

Choose a reason for hiding this comment

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

Renamed for clarity, but kept it outside the test context.

Copy link
Member

Choose a reason for hiding this comment

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

Makes sense. I was wrong about the parameterization

* @param {ERef<Subscriber<T>>} subscriberP
* @returns {Promise<Notifier<T>>}
*/
export const makeNotifierFromSubscriber = async subscriberP => {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
export const makeNotifierFromSubscriber = async subscriberP => {
export const makeNotifierFromSubscriber = async subscriber => {

I assume P is for "Promise" but that's not exactly what this is.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's an ERef, which may be a promise. I think we do use this pattern to highlight that potential.

Copy link
Member

Choose a reason for hiding this comment

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

I've also seen P for Presence, kind of the opposite.

I don't think we have any consistent guidelines on this but I would make the case that when possible we rely on the type system for whether something is a promise or not. If there's no need to bind both the promise and the resolved value then use the simpler name. non-blocking request.

@gibson042 gibson042 force-pushed the gh-5413-makeNotifierFromSubscriber branch from 3b14845 to 137088c Compare July 8, 2022 19:06
@gibson042 gibson042 force-pushed the gh-5413-makeNotifierFromSubscriber branch from 137088c to f40b7ed Compare July 8, 2022 19:08
@gibson042
Copy link
Member Author

@turadg f40b7ed addresses everything except the "floating promises" concern... what kind of change are you expecting for that?

Copy link
Member

@turadg turadg left a comment

Choose a reason for hiding this comment

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

LG. I'll approve when the three new eslint warnings are resolved.

@gibson042
Copy link
Member Author

I didn't see the promise ones locally. Anyway, resolved and pushed.

Copy link
Member

@turadg turadg left a comment

Choose a reason for hiding this comment

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

👍

* @param {ERef<Subscriber<T>>} subscriberP
* @returns {Promise<Notifier<T>>}
*/
export const makeNotifierFromSubscriber = async subscriberP => {
Copy link
Member

Choose a reason for hiding this comment

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

This isn't an async function:

Suggested change
export const makeNotifierFromSubscriber = async subscriberP => {
export const makeNotifierFromSubscriber = subscriberP => {

I don't think it needs to return Promise either. Can't it return the Notifier as makeNotifierFromAsyncIterable does?

@turadg
Copy link
Member

turadg commented Jul 8, 2022

Working on #5704 I ran into some issues using this so I took another look and found a few things to address:

getUpdateSince() always consults the source subscribeAfter() rather than
using a possibly-stale local cache.
Copy link
Member

@turadg turadg left a comment

Choose a reason for hiding this comment

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

🎉 I rebased my branch onto this version and the contract tests pass!

:shipit: 😸

@turadg turadg added the automerge:squash Automatically squash merge label Jul 13, 2022
@mergify mergify bot merged commit 077718a into master Jul 14, 2022
@mergify mergify bot deleted the gh-5413-makeNotifierFromSubscriber branch July 14, 2022 00:18
turadg added a commit that referenced this pull request Jul 14, 2022
* fix(notifier): Make makeAsyncIterableFromNotifier lossy

Cherry-picked from gh-5413-lossy-makeNotifierFromAsyncIterable.
See #5695 .

* fix(notifier): Revert "Make makeAsyncIterableFromNotifier lossy"

Eager consumption led to infinite loops; see
#5695 for context.

* feat(notifier): Add makeNotifierFromSubscriber

Fixes #5413

* test(notifier): Update per code review

* chore(notifier): Resolve lint warnings

* fix(notifier): Align makeNotifierFromSubscriber with makeNotifierKit

getUpdateSince() always consults the source subscribeAfter() rather than
using a possibly-stale local cache.

* fix master merge

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: Turadg Aleahmad <turadg@agoric.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge:squash Automatically squash merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

notifier returned by makeNotifierFromAsyncIterable is lossless
2 participants