-
Notifications
You must be signed in to change notification settings - Fork 8.2k
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
[Ingest pipelines] Test pipeline enhancements #74964
[Ingest pipelines] Test pipeline enhancements #74964
Conversation
b328e84
to
1f2ca4a
Compare
…pipeline_enhancements
…pipeline_enhancements
const outProcessor = { | ||
[type]: { | ||
...options, | ||
}, | ||
}; | ||
|
||
if (onFailure?.length) { | ||
outProcessor[type].on_failure = convertProcessors(onFailure); | ||
} else if (onFailure) { | ||
outProcessor[type].on_failure = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jloleysens can you verify I didn't introduce any regressions by deleting this line? It was causing issues when calling the simulate API, as the on_failure
field cannot be an empty array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ok, I think this should be fine. The thinking here was that we return to the caller the same set of values that was passed in - so if they passed in an empty array, we would return one. That being said, I am happy to collapse that value because the ES API accepts undefined for that value.
Not accepting an empty array is kinda weird though!
Pinging @elastic/es-ui (Team:Elasticsearch UI) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work @alisonelizabeth 🍾! I think this is a really exciting change and am eager to see it get to users :)
Bugs
While following the steps in the PR description I got to step 2, pressed the "Run the pipeline" button and nothing happened. This is what I saw in the console
Code
I've left some non-blocking comments in the code, the one I think most useful to hear your thoughts on would be regarding moving the call to test pipeline context into pipeline_processors_editor and only using it from within there.
const { | ||
state: { processors }, | ||
} = usePipelineProcessorsContext(); | ||
const { testPipelineData, setCurrentTestPipelineData } = useTestPipelineContext(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the TestPipelineContext is available to processors_header.tsx
but I think it might provide a slightly better decoupling between processors_header
and pipeline_processors_editor
:
- Update the
pipeline_processors_editor
to just export<ManageDocumentsButton />
component (I made this up but it would wrapDocumentsDropdown
andAddDocumentsButton
) which contains the logic for showing/hiding the flyout - Only call
useTestPipelineContext
from within new 👆🏻 button component - Drive the state updates to test pipeline context from within
pipeline_processors_editor
(call tosetCurrentTestPipelineData
). - Remove
DocumentsDropdown
,AddDocumentsButton
,TestPipelineFlyout
andTestPipelineFlyoutTab
from pipeline processors exports.
Not major, but I believe this would be cleaner. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great point. I agree; I think this would be cleaner. I think I may have started in this direction, but can't remember now why I pivoted 🤔 . I'll look into refactoring this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up creating a component called TestPipelineActions
that renders the add documents button/documents dropdown and the output button. The pipeline processor editor exports this as well as the DocumentsDropdown
, since the dropdown is also reused in the output tab of each processor. Let me know what you think!
<EuiFlexItem grow={false} className="documentsDropdown__selectContainer"> | ||
<EuiSelect | ||
compressed | ||
options={getDocumentOptions(documents!)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be able to remove the !
from documents!
label: string; | ||
} | ||
|
||
const mapProcessorStatusToIcon: Record<string, ProcessorStatusIcon> = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could string
be typed as ProcessorStatus
here?
} | ||
|
||
export const PipelineProcessorsItemStatus: FunctionComponent<Props> = ({ processorStatus }) => { | ||
const { icon, iconColor, label } = mapProcessorStatusToIcon[processorStatus]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit; I think for future refactors it could make this code a bit safer if we define a fallback value for when processorStatus
does not map to an expected value. Also happy if we leave that to throw an exception but if the value comes straight from ES slightly more robust might be good.
const { services } = useKibana(); | ||
|
||
const setCurrentTestPipelineData = useCallback((data: Action): void => { | ||
dispatch(data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is not necessary to wrap this dispatch in a useCallback
as the function is not new on every render. At least according to this fella (https://kentcdodds.com/blog/how-to-use-react-context-effectively#what-about-dispatch-type-typos). So you can call dispatch
directly.
const result = { ...currentResult }; | ||
const resultId = result.tag; | ||
|
||
if (index !== 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we skip the first index here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first processor result would not have a previous result 😄 . I can update the code comment below to be more clear.
I also realized earlier today that this logic may need to be more complex. For example, if the previous processor was skipped there would also not be a previous result. Interested in your thoughts here - is this OK, or does it make more sense to display the last successful processor output?
return convertedProcessors; | ||
}; | ||
|
||
export const serialize = ({ processors, onFailure }: SerializeArgs): SerializeResult => { | ||
export const serialize = ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit; a default value and renaming to copyIdToTag
could be extra clear :)
Then we document like
/**
* param@ processor: The deserialized processor to convert
* param@ copyIdToTag: For simulation, we add the "tag" field equal to the internal processor id so that we can map the simulate results to each processor
*/
const serialize = (processor: ProcessorInternal, copyIdToTag: boolean = false)
I think doing this on interface could be even better, but understand that is more of a refactor:
interface SerializeArgs {
/**
* The deserialized processor to convert
*/
processor: ProcessorInternal;
/**
* For simulation, we add the "tag" field equal to the internal processor id so that we can map the simulate results to each processor
*/
copyIdToTag: boolean;
}
export const serialize = ({
pipeline: { processors, onFailure },
copyIdToTag = false,
}: SerializeArgs): SerializeResult => {
@jloleysens thanks for the very helpful review! I will address the feedback today/tomorrow. In the meantime, I'm not able to reproduce the error you are seeing. Are you running with the latest ES snapshot? Maybe we can zoom tomorrow if you're still having issues. |
Ah that could be the case! I thought my snapshot was recent enough, but it might be the case that it is not. Will re-test 👍 |
@jloleysens I believe I addressed all of your feedback. Let me know what you think, and reach out if you still run into issues testing. Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for addressing the PR feedback @alisonelizabeth ! This is looking really great.
I have a few UX related questions that I think we can address in (a) follow up PR(s):
As a user, it wasn't exactly clear to me how I could get out of live testing mode once I had added documents to test with. This is not a major issue but I thought could merit being intentional about in our design. The only instance I think something like this could be useful in is when a user wants to silence constant feedback or when they are working under high network latency conditions. I tried clearing the docs in the flyout but the form prevented me from doing so. I'd imagine clearing the docs should also clear all of the current processor statuses.
I understand that being "dropped" is a state we get back from ES simulate, but perhaps in this case it would be better suited if the drop processor had a green tick (i.e., it did it's job).
Bug
I don't mind if we address this in follow up PR, but if I submit a simulation with a badly configured processor currently the processor states do not update and the user does not receive an indication that their processor is incorrectly configured unless they try to create the pipeline or open the output flyout. With the following 👇🏻 configuration for "Set" and documents loaded up the UI still rendered a green tick (from my initial good configuration).
Perhaps we should render the entire pipeline's processors in "not run" status when simulate returns a 400.
Component Integration Tests
I think it would be good to add them as the very next thing so that following PRs can benefit from them 👍
const outProcessor = { | ||
[type]: { | ||
...options, | ||
}, | ||
}; | ||
|
||
if (onFailure?.length) { | ||
outProcessor[type].on_failure = convertProcessors(onFailure); | ||
} else if (onFailure) { | ||
outProcessor[type].on_failure = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ok, I think this should be fine. The thinking here was that we return to the caller the same set of values that was passed in - so if they passed in an empty array, we would return one. That being said, I am happy to collapse that value because the ES API accepts undefined for that value.
Not accepting an empty array is kinda weird though!
Thanks @jloleysens for the second review!
This is a great point and not something I had thought about yet. I'll work with Michael on this and address in a separate PR.
I think I originally only showed success/fail statuses per processor (i.e., error_ignored, skipped, and dropped == success). However, when I held the initial stakeholder review, feedback I received was that it would be helpful to call out each status. The icons I currently have are probably not the best representation. I've mentioned this to Michael already, and he's going to look into it.
Good catch! For now, I reset the output when there is an error (back to "inactive" state), but I think there's probably more that could be done here to help the user and possibly surface the error.
Agreed! Plan to work on tests next. |
💚 Build SucceededBuild metrics@kbn/optimizer bundle module count
async chunks size
page load bundle size
History
To update your PR or re-run it, just comment with: |
This PR improves the pipeline debugging workflow in the ingest node pipelines UI.
At this point, I consider this feature functionally complete. However, I think there is still room for UX improvements, which I will continue to work on with Michael this week. Feel free to leave any thoughts on the PR as well.
Other notes:
tag
field is added to the simulate API request as a way to map the results to each processor in the pipeline. If a user already has atag
field defined, it will be temporarily overridden for this call. I don't foresee any issues with this, but wanted to call it out.pipeline
processor. Theverbose
response does not include the processor output in the response; it only returns the status. Also, if you test with apipeline
processor that results in an error, the simulate API times out with a 502 Bad Gateway error. Jake L. is out this week, but I will discuss this with him when he returns.How to test
Screenshots
Release note
This features refines the debugging user experience when creating or editing an ingest node pipeline in the existing Ingest Node Pipelines UI. Once a sample document(s) is provided, the pipeline is executed. The UI highlights the status of each processor, and shows the user how their sample documents change shape at each step in the pipeline.