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

[Enterprise Search] Create HttpLogic Kea store, add http interceptors, and manage error connecting at top app-level #75790

Merged
merged 7 commits into from
Aug 24, 2020

Conversation

cee-chen
Copy link
Contributor

@cee-chen cee-chen commented Aug 24, 2020

Summary

I strongly recommend following along by commit! 🔍

This PR:

  • Changes all "Error connecting to Enteprise Search" response status codes from 404 to 502, which is a more accurate & distinct status code which we can use to granularly catch error connecting state (vs. our own 404s)
  • Set ups new a new HttpLogic Kea store, which allows us to
    • connect() directly to HttpLogic in other Kea logic files that need to make http calls (instead of passing in http manually via args - cc @scottybollinger)
    • Set http interceptors/listeners & remove the interceptors on unmount within Kea
    • Share state derived from http (e.g. errorConnecting, readOnlyMode) between both AS & WS (but allow each app to handle that state differently if needed)
  • Moves the error connecting component to the top-level App instead of requiring every component to catch/manage its own state/return
  • Minor App Search cleanup - moves a lot of child components (LoadingState, EmptyState, EngineOverviewHeader) into subfolders of EngineOverview, instead of top-level components. This originally made sense for the MVP but no longer makes sense with more views coming in

QA

When Enterprise Search is unavailable on load

  • Start up Kibana on this branch but do NOT start (or STOP) Enterprise Search
  • Go to Workplace Search and confirm that the "Error connecting" prompt appears
  • Go to App Search and confirm that the "Error connecting" prompt appears
  • Also open your devtools and log XHR requests - on refresh, confirm that App Search polls /api/enterprise_search/config_data (which returns a 502 Bad Gateway)

When Enterprise Search becomes unavailable mid-session

Regression testing

  • Confirm the Workplace Search overview page works before as normal and loads all data as normal
  • Confirm the App Search Engines loading state and empty state work as before

Checklist

@@ -67,6 +68,7 @@ export const renderApp = (
>
<LicenseProvider license$={plugins.licensing.license$}>
<Provider store={store}>
<HttpProvider http={core.http} errorConnecting={errorConnecting} />
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just wanted to make a quick note here: I left http in KibanaContext for now:

https://github.com/elastic/kibana/blob/94b5da6ae91fe2a3bf30a1c1945bc4bc8a1b061c/x-pack/plugins/enterprise_search/public/applications/index.tsx#L59-L63

although I'm 50/50 on whether to remove it and have the only way for us to access http be from const { http } = useValues(HttpLogic) (vs also being able to do const { http } = useContext(KibanaContext)).

They both reference the same global Kibana http instance so it's not a question of accidentally using the wrong var or anything, it's just 2 different ways of calling http which may end up being confusing.

I will say that IMO useContext(KibanaContext) is significantly easier to mock and spy on in Jest tests (you just listen for mockKibanaContext.http changes) - whereas I ran into a super huge headache trying to pass a mockContext into a HttpLogic mock for some baffling reason.

Either way we decide, I definitely don't plan on removing all instances of const { http } = useContext(KibanaContext) in this PR, to try to keep it smaller for now. @scottybollinger / @JasonStoltz would definitely appreciate your thoughts if we should eventually remove them or if it's not a huge deal to have 2 ways of accessing http.

Copy link
Contributor

Choose a reason for hiding this comment

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

I personally don't mind leaving both instance types since they reference the same thing and especially if it makes testing easier

Copy link
Member

Choose a reason for hiding this comment

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

Yeah I'm 👍 for just leaving it as is for now and seeing how it goes. We could always change it later.

@cee-chen cee-chen added v7.10.0 release_note:skip Skip the PR/issue when compiling release notes Feature:Plugins labels Aug 24, 2020
- This allows us to:
  - connect() directly to HttpLogic in other Kea logic files that need to make http calls, instead of passing in http manually via args
  - Set http interceptors & remove them interceptors on unmount within Kea
  - Share state derived from http (e.g. errorConnecting, readOnlyMode) between both AS & WS (but allow each app to handle that state differently if needed)

+ Refactors necessary for these changes:
  - Kea types - add events key, clarify that mount returns an unmount function, fix reducer state type
  - ReactDOM unmount - remove resetContext({}), was preventing logic from unmounting properly
- Since main app is now handling errorConnecting
- http can now be connected directly from HttpLogic Kea store, so no need to pass it
+ minor cleanup in logic_overview.test.ts - remove unneeded unmount(), act(), switch to HttpLogic mock
- delete old ErrorState component
- move LoadingState, EmptyState, and EngineOverviewHeader into subfolders in engine_overview
Copy link
Contributor

@richkuz richkuz left a comment

Choose a reason for hiding this comment

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

Nice! 💯

@@ -52,7 +52,7 @@ export function registerEnginesRoute({ router, config, log }: IRouteDependencies
log.error(`Cannot connect to App Search: ${e.toString()}`);
if (e instanceof Error) log.debug(e.stack as string);

return response.notFound({ body: 'cannot-connect' });
return response.customError({ statusCode: 502, body: 'cannot-connect' });
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we distinguish authentication errors separately?

Copy link
Contributor Author

@cee-chen cee-chen Aug 24, 2020

Choose a reason for hiding this comment

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

Ahhh hm, great call. I can definitely try in a separate PR - I think I'd probably build off what Jason is doing in #75487 and check for the /login redirect there (since eventually all API endpoints should be using that helper).

We have to be careful about what statusCode we use for authentication though. If we try 401 or 403 I believe Kibana automatically responds to that by logging the Kibana user out (which is not what we want lmao). I'm tempted to keep the status code the same (502) and simply modify the body to specify a "Cannot authenticate this user" error vs a generic "Cannot connect to Enterprise Search" fallback.

What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

Definitely, separate PR. Was just thinking out loud.

If we try 401 or 403 I believe Kibana automatically responds to that by logging the Kibana user out (which is not what we want lmao).

Oy, definitely not. Does Kibana install some invasive, global hook to catch all 401/403's? I am not close enough to the code, but returning a 401/403 wrapped inside a 502 feels broken. Anyway, we can discuss separately. I don't intend to hold up progress on this PR on a tangential issue. Incremental progress FTW.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I haven't dug through their code super deeply but yeah I believe every http request/response gets run through their global http lib (both on the client-side and server-side). I definitely see why and we get plenty of advantages of doing so, it's just in this one scenario that we don't particularly want that side-effect. I remember spending a real confused half hour trying to figure out why I was getting logged out during my initial MVP work though haha.

Copy link
Contributor Author

@cee-chen cee-chen Aug 24, 2020

Choose a reason for hiding this comment

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

Also there's some nuance to the status codes here - while it's true that the user is unauthorized in Enterprise Search, they're not necessarily unauthorized in Kibana (which is generating the status code), and as such it's not necessarily a client error / a 4xx doesn't necessarily apply.

I do think the 502 status code is the most generic while still applying to our use case:

This error response means that the server, while working as a gateway to get a response needed to handle the request, got an invalid response

In this case, a /login redirect (unauthenticated in Enterprise Search) qualifies as an "invalid response" just IMO.

Copy link
Member

Choose a reason for hiding this comment

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

I agree with you there Constance 👍

@cee-chen cee-chen changed the title Http logic [Enterprise Search] Create HttpLogic Kea store, add http interceptors, and manage error connecting at top app-level Aug 24, 2020
Copy link
Contributor

@scottybollinger scottybollinger left a comment

Choose a reason for hiding this comment

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

LGTM! Left a comment about a test suite name but feel free to merge if that's as intended

Copy link
Contributor Author

@cee-chen cee-chen left a comment

Choose a reason for hiding this comment

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

I'm being lazy and making these changes via GitHub since my current local is all mangled w/ flash messages shenanigans

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Build metrics

@kbn/optimizer bundle module count

id value diff baseline
enterpriseSearch 200 +3 197

async chunks size

id value diff baseline
enterpriseSearch 349.0KB +6.6KB 342.5KB

page load bundle size

id value diff baseline
enterpriseSearch 21.8KB +31.0B 21.8KB

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@JasonStoltz
Copy link
Member

Great changes Constance, thank you.

cee-chen pushed a commit that referenced this pull request Aug 25, 2020
…, and manage error connecting at top app-level (#75790) (#75821)

* [Setup] Change error connecting status code to 502

- For clearer error handling

* Set up new HttpProvider/Logic Kea store & listeners

- This allows us to:
  - connect() directly to HttpLogic in other Kea logic files that need to make http calls, instead of passing in http manually via args
  - Set http interceptors & remove them interceptors on unmount within Kea
  - Share state derived from http (e.g. errorConnecting, readOnlyMode) between both AS & WS (but allow each app to handle that state differently if needed)

+ Refactors necessary for these changes:
  - Kea types - add events key, clarify that mount returns an unmount function, fix reducer state type
  - ReactDOM unmount - remove resetContext({}), was preventing logic from unmounting properly

* Update AS & WS to show error connecting component at app level

* [WS] Remove errorConnecting logic & http arg from Overview

- Since main app is now handling errorConnecting
- http can now be connected directly from HttpLogic Kea store, so no need to pass it
+ minor cleanup in logic_overview.test.ts - remove unneeded unmount(), act(), switch to HttpLogic mock

* [AS] Add top-level ErrorConnecting component & remove error logic from EngineOverview

* [AS] Clean up/move EngineOverview child components into subfolder

- delete old ErrorState component
- move LoadingState, EmptyState, and EngineOverviewHeader into subfolders in engine_overview

* PR feedback: Update test assertions 404 copy
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:Plugins release_note:skip Skip the PR/issue when compiling release notes v7.10.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants