diff --git a/awx/ui/src/screens/Job/useWsJob.js b/awx/ui/src/screens/Job/useWsJob.js index 5ad7faf8a6..5c08a995e9 100644 --- a/awx/ui/src/screens/Job/useWsJob.js +++ b/awx/ui/src/screens/Job/useWsJob.js @@ -4,6 +4,7 @@ import { getJobModel } from 'util/jobs'; export default function useWsJob(initialJob) { const [job, setJob] = useState(initialJob); + const [pendingMessages, setPendingMessages] = useState([]); const lastMessage = useWebsocket({ jobs: ['status_changed'], control: ['limit_reached_1'], @@ -13,30 +14,48 @@ export default function useWsJob(initialJob) { setJob(initialJob); }, [initialJob]); + const processMessage = (message) => { + if (message.unified_job_id !== job.id) { + return; + } + + if ( + ['successful', 'failed', 'error', 'cancelled'].includes(message.status) + ) { + fetchJob(); + } + setJob(updateJob(job, message)); + }; + + async function fetchJob() { + const { data } = await getJobModel(job.type).readDetail(job.id); + setJob(data); + } + useEffect( () => { - async function fetchJob() { - const { data } = await getJobModel(job.type).readDetail(job.id); - setJob(data); - } - - if (!job || lastMessage?.unified_job_id !== job.id) { + if (!lastMessage) { return; } - - if ( - ['successful', 'failed', 'error', 'cancelled'].includes( - lastMessage.status - ) - ) { - fetchJob(); - } else { - setJob(updateJob(job, lastMessage)); + if (job) { + processMessage(lastMessage); + } else if (lastMessage.unified_job_id) { + setPendingMessages(pendingMessages.concat(lastMessage)); } }, [lastMessage] // eslint-disable-line react-hooks/exhaustive-deps ); + useEffect(() => { + if (!job || !pendingMessages.length) { + return; + } + pendingMessages.forEach((message) => { + processMessage(message); + }); + setPendingMessages([]); + }, [job, pendingMessages]); // eslint-disable-line react-hooks/exhaustive-deps + return job; } diff --git a/licenses/django-qsstats-magic.txt b/licenses/django-qsstats-magic.txt deleted file mode 100644 index adef47b952..0000000000 --- a/licenses/django-qsstats-magic.txt +++ /dev/null @@ -1,24 +0,0 @@ -Copyright (c) 2010, Matt Croydon, Mikhail Korobov -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the tastypie nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL MATT CROYDON BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.