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

refactor: Support all the webs #1123

Closed

Conversation

russell-dot-js
Copy link
Contributor

@russell-dot-js russell-dot-js commented Apr 29, 2020

  • Collapse stream-collector-browser and stream-collector-native into stream-collector-web
  • Update FetchHttpHandler to return blob if stream not implemented

Issue #, if available:
#1107

Description of changes:

  • Remove stream-collector-browser and stream-collector-native in favor of generic stream-collector-web
  • Update FetchHttpHandler to always return blob if stream not implemented

The real changes are here and (starting) here. Rest is find-replace.

Open questions

  • Naming of stream-collector-web? I would normally call it stream-collector-client, considering it's for use client-side, but don't want it to be easily confused with the actual (AWS) clients in the sdk. Could also go for something like stream-collector-fetch to demonstrate coupling with FetchHttpHandler
  • Ok that since, this is technically a new package, I started it at 1.0.0-beta.0?
  • What if we collapsed the "HttpHandlers" and "StreamCollectors" into a single package? E.g. rather than mixing and matching HttpHandlers and StreamCollectors, they always come together. So if you use FetchHttpHandler, you get the FetchStreamCollector. etc.
  • Can we get rid of the "bufferBody" option in FetchHttpHandler? There's no reason for native to say "never give me a stream" - my assumption is that it will be supported, eventually, and as long as we support both scenarios at run-time, we're good to go.
  • Is there a preference to keep stream-collector-browser and stream-collector-native separate, even though they'd both delegate to this same package? My thought was that since this is still in beta, and we can get away with deleting stuff, I didn't see a reason to create (what's arguably) technical debt.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@russell-dot-js russell-dot-js force-pushed the support-all-the-browsers branch from cb7e413 to 41634df Compare April 29, 2020 03:05
@aws-sdk-js-automation
Copy link

AWS CodeBuild CI Report

  • CodeBuild project: sdk-staging-test
  • Commit ID: cb7e413
  • Result: FAILED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@russell-dot-js russell-dot-js force-pushed the support-all-the-browsers branch from 41634df to d455ef9 Compare April 29, 2020 03:06
@russell-dot-js russell-dot-js changed the title Support all the webs refactor: Support all the webs Apr 29, 2020
@aws-sdk-js-automation
Copy link

AWS CodeBuild CI Report

  • CodeBuild project: sdk-staging-test
  • Commit ID: 41634df
  • Result: FAILED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@russell-dot-js
Copy link
Contributor Author

Crap. I forgot to update stream-collector-web/CHANGELOG after the git mv from stream-collector-native. Will wait for feedback to open questions in PR description before buttoning up.

@aws-sdk-js-automation
Copy link

AWS CodeBuild CI Report

  • CodeBuild project: sdk-staging-test
  • Commit ID: d455ef9
  • Result: FAILED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@russell-dot-js russell-dot-js force-pushed the support-all-the-browsers branch 2 times, most recently from 0e6f077 to d638485 Compare April 29, 2020 03:23
@aws-sdk-js-automation
Copy link

AWS CodeBuild CI Report

  • CodeBuild project: sdk-staging-test
  • Commit ID: 0e6f077
  • Result: FAILED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@aws-sdk-js-automation
Copy link

AWS CodeBuild CI Report

  • CodeBuild project: sdk-staging-test
  • Commit ID: d638485
  • Result: FAILED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

Copy link
Contributor

@AllanZhengYP AllanZhengYP left a comment

Choose a reason for hiding this comment

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

The new name stream-collector-web sounds good to me. Will need @trivikr for another look. We also need to confirm whether removing bufferBody config from fetch-http-handler will affect Amplify(I don't think so).

// TODO can we get rid of this? is there a scenario where a client wants to
// insist on a Blob, even if stream is implemented? regardless, comment above
// is outdated, this is not only useful in ReactNative due to variety of fetch
// implementations
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the same way. If we rely on dynamicly detecting the ReadableStream implementation in the environment, we should remove it.

@AllanZhengYP
Copy link
Contributor

Hey @russell-dot-js

Very awesome PR! Regarding your questions:

Is there a preference to keep stream-collector-browser and stream-collector-native separate, even though they'd both delegate to this same package? My thought was that since this is still in beta, and we can get away with deleting stuff, I didn't see a reason to create (what's arguably) technical debt.

Given we prefer to return body in blob or ReadableStream dynamicly from fetch-http-handler, we should also merge the 2 difference stream collector.

What if we collapsed the "HttpHandlers" and "StreamCollectors" into a single package? E.g. rather than mixing and matching HttpHandlers and StreamCollectors, they always come together. So if you use FetchHttpHandler, you get the FetchStreamCollector. etc.

Unfortunately we cannot do it. For any service/operations supporting streaming payload, we don't call StreamCollectors to the response, instead we return the stream from low-level http handler to users directly. In these case, the http handlers doesn't have the prior knowledge of whether the response is from an operation with streaming member.

Generally very solid PR. I'd like to get some more set of eyes the review the solution. Ones we decide to go with this solution, I can provide some help with the code generation. Basically, we don't work directly on clients folder, because they are generated. Instead, we make code change to our code generator in Java, or the lower level smithy typescript generator. Don't worry about it just now, we will provide all the guides needed.

@AllanZhengYP AllanZhengYP requested a review from trivikr April 29, 2020 18:54
@russell-dot-js
Copy link
Contributor Author

russell-dot-js commented Apr 29, 2020

Hey @russell-dot-js

Very awesome PR!

Thank you!! Happy to help.

Is there a preference to keep stream-collector-browser and stream-collector-native separate, even though they'd both delegate to this same package? My thought was that since this is still in beta, and we can get away with deleting stuff, I didn't see a reason to create (what's arguably) technical debt.

Given we prefer to return body in blob or ReadableStream dynamicly from fetch-http-handler, we should also merge the 2 difference stream collector.

Noted

What if we collapsed the "HttpHandlers" and "StreamCollectors" into a single package? E.g. rather than mixing and matching HttpHandlers and StreamCollectors, they always come together. So if you use FetchHttpHandler, you get the FetchStreamCollector. etc.

Unfortunately we cannot do it. For any service/operations supporting streaming payload, we don't call StreamCollectors to the response, instead we return the stream from low-level http handler to users directly. In these case, the http handlers doesn't have the prior knowledge of whether the response is from an operation with streaming member.

Curious -- are you sure we can't do this?

Example:

interface HttpProvider<T> {
  handler: HttpHandler<T>;
  streamCollector: StreamCollector<T>;
}

// could be generic or not, doesn't really matter
// T might be ReadableStream | Blob for web, or Readable for node.

const webHttpProvider: HttpProvider<ReadableStream | Blob> = {
  handler: fetchHttpHandler,
  streamCollector: streamCollectorWeb,
};

const nodeHttpProvider: HttpProvider<Readable> = {
  handler: nodeHttpHandler,
  streamCollector: streamCollectorNode,
};

// clients would have single arg httpProvider, rather than args 
// httpHandler and streamCollector.

For the S3 client, the streamCollector would be ignored, but for most clients, it would be used.

Generally very solid PR. I'd like to get some more set of eyes the review the solution. Ones we decide to go with this solution, I can provide some help with the code generation. Basically, we don't work directly on clients folder, because they are generated. Instead, we make code change to our code generator in Java, or the lower level smithy typescript generator. Don't worry about it just now, we will provide all the guides needed.

Got it! I knew there was some code gen for the clients, but assumed that since the clients were checked in, they were not code-genned. For my own understanding, can you please clarify why the generated code is checked in? Is this to speed up CI, to keep every change in version control to ease human debugging, or to facilitate one-off edits of generated code (seems risky)?

Also, I am curious why I have tests failing in CI that did not pass locally. yarn test:all passed locally... perhaps I should open an issue regarding unclear documentation around how to test? I'm also happy to look into #1092, adding more transparency to the CI process would help "outsiders" like me contribute.

@russell-dot-js russell-dot-js force-pushed the support-all-the-browsers branch from d638485 to ba7274e Compare April 29, 2020 21:18
@russell-dot-js
Copy link
Contributor Author

russell-dot-js commented Apr 29, 2020

@AllanFly120 I've amended my commit (do you prefer squashed PR's?) removing "bufferBody", and fixing the failing tests. I had to update the tests to not return "body", as the tests were returning strings, not ReadableStreams, and we do not have a ReadableStream polyfill set up for the node test environment (do we want one? It would be nice to add some unit tests demonstrating that it properly handles ReadableStream if implemented, and falls back to blob.)

See changes in packages/fetch-http-handler/src/fetch-http-handler.ts and packages/fetch-http-handler/src/fetch-http-handler.spec.ts

Also, regarding my question about yarn test:all -- it looks like test:all does not actually run all tests, it is defined as
"test:all": "jest --coverage --passWithNoTests && lerna run test --scope @aws-sdk/stream-collector-web --scope @aws-sdk/hash-blob-browser",

Were those scopes accidentally committed, or is the intent of test:all to only test those two packages?

@aws-sdk-js-automation
Copy link

AWS CodeBuild CI Report

  • CodeBuild project: sdk-staging-test
  • Commit ID: ba7274e
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@russell-dot-js
Copy link
Contributor Author

@AllanFly120 / @trivikr just wanted to check in on this? Per #1121 (comment), @Stereobit also has users in a tough spot right now. Maybe we can at least release the quick fix in #1121 while this is reviewed?

@AllanZhengYP
Copy link
Contributor

@russell-dot-js Hi, sorry for the late response. Can you remove all the diffs in clients folder from this PR and only keep the fetch-http-handler and event-collector-web changes? I will open another PR with updated clients to coordinate with this PR.

// can we just check for existence of response.body, as that should be
// guaranteed to be a ReadableStream if it exists?
const hasResponseStream = typeof ReadableStream === 'function' &&
response.body instanceof ReadableStream;
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a good point. I agree that we can just check response.body for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done and done

Was hoping you could response to my questions here:
#1123 (comment)
and here?
#1123 (comment)

AllanZhengYP added a commit to AllanZhengYP/smithy-typescript that referenced this pull request May 12, 2020
@russell-dot-js russell-dot-js force-pushed the support-all-the-browsers branch from ba7274e to 0eedacd Compare May 12, 2020 20:58
* Collapse stream-collector-browser and stream-collector-native into stream-collector-web
* Update FetchHttpHandler to return blob if stream not implemented
@russell-dot-js russell-dot-js force-pushed the support-all-the-browsers branch from 0eedacd to 0bc10e8 Compare May 12, 2020 21:00
@codecov-io
Copy link

codecov-io commented May 12, 2020

Codecov Report

Merging #1123 into master will decrease coverage by 0.00%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1123      +/-   ##
==========================================
- Coverage   73.54%   73.53%   -0.01%     
==========================================
  Files         283      284       +1     
  Lines       13014    13023       +9     
  Branches     3030     3035       +5     
==========================================
+ Hits         9571     9577       +6     
- Misses       3443     3446       +3     
Impacted Files Coverage Δ
...kages/fetch-http-handler/src/fetch-http-handler.ts 93.47% <0.00%> (-1.98%) ⬇️
packages/util-body-length-browser/src/index.ts 71.42% <0.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 65a3658...0bc10e8. Read the comment docs.

@aws-sdk-js-automation
Copy link

AWS CodeBuild CI Report

  • CodeBuild project: sdk-staging-test
  • Commit ID: 0eedacd
  • Result: FAILED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@aws-sdk-js-automation
Copy link

AWS CodeBuild CI Report

  • CodeBuild project: sdk-staging-test
  • Commit ID: 0bc10e8
  • Result: FAILED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@aws-sdk-js-automation
Copy link

AWS CodeBuild CI Report

  • CodeBuild project: sdk-staging-test
  • Commit ID: 86dd467
  • Result: FAILED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@russell-dot-js russell-dot-js force-pushed the support-all-the-browsers branch from 86dd467 to fb381d9 Compare May 12, 2020 21:31
@aws-sdk-js-automation
Copy link

AWS CodeBuild CI Report

  • CodeBuild project: sdk-staging-test
  • Commit ID: fb381d9
  • Result: FAILED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@AllanZhengYP
Copy link
Contributor

Hi @russell-dot-js

Curious -- are you sure we can't do this?

After putting more thoughts on it I think:

✅ we can colapse fetch-request-handler and stream-collector-web into the same package; Also node-http-handler and stream-collector-node into the same package. Because they always co-exist.
❌ we should not put the handler and stream collector under the same interface(e.g. nodeHttpProvider). Because they belong to different request handling stage and should be decoupled for extensibility of SDK, here's details:

Request handler are supposed to be a thin layer over the runtime primitives, it must return the raw low level response payload. It serves as the core of service client's middleware stack regardless of the service model. However, stream collector is a util function, although very commonly used, that defined by the service model. It is generated when the service needs structured response.

Why is this difference important? Because V3 SDK is designed with a lot of flexibility. Any AWS client is extended from a white-labeled client that only knows the low-level request handler(requestHandler). This design enables us to support any non-http services in the future like WebSocket, MQTT and even unstandard JS runtime like JerryScript. In the future, we'd like to support everyone to generate their own V3-like SDK on top of the white-labeled client, it doesn't make much sense if we require a stream collector in the white-labeled client.

I hope my explanation makes sense to you.

@AllanZhengYP
Copy link
Contributor

@russell-dot-js

It would be nice to add some unit tests demonstrating that it properly handles ReadableStream if implemented, and falls back to blob.)

We used string body because we simply run the test in Node runtime. It will be awesome if we ca have a webstream polyfill test.

I think you can add the test in a separate PR if you want because many Amplify users are still blocked by this issue in SDK. I'd like get this fix merged in earlier

Were those scopes accidentally committed, or is the intent of test:all to only test those two packages?

The scoped test script only runs in the 2 packages. Because the unit test in the packages are run in puppeteer, so we call the test script in the 2 packages explicitly.

AllanZhengYP added a commit to AllanZhengYP/smithy-typescript that referenced this pull request May 14, 2020
@AllanZhengYP
Copy link
Contributor

@russell-dot-js
Hi, I'm working on another PR adopting your commits from this PR. I will post the PR when it's ready.

@AllanZhengYP AllanZhengYP added the closing-soon This issue will automatically close in 4 days unless further comments are made. label May 15, 2020
AllanZhengYP added a commit to smithy-lang/smithy-typescript that referenced this pull request May 18, 2020
* Use web universal fetch handler and stream collector

Correspond to aws/aws-sdk-js-v3#1123

* move runtime-specific stream collectors to individual request handler package
@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jan 20, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
closing-soon This issue will automatically close in 4 days unless further comments are made.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants