Skip to content

Commit

Permalink
Avoid API queries for some events
Browse files Browse the repository at this point in the history
These events change the state in a predictable way. Avoid the expensive
updateContainer() call for these, to avoid multiple calls overlapping
each other. See containers/podman#19124

The exact `StartedAt` value for the "start" event is unfortunately not
part of the event data, but we can approximate it very well with the
event time stamp. This doesn't have to be 100% correct: The only place
where we use that is the restart detection in testLifecycleOperations.
Adjust that to not require the data-started-at to be identical to the
CLI output, just that it changes.
  • Loading branch information
martinpitt committed Jul 14, 2023
1 parent fc382cc commit d3cb07d
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 9 deletions.
54 changes: 48 additions & 6 deletions src/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import ContainerHeader from './ContainerHeader.jsx';
import Containers from './Containers.jsx';
import Images from './Images.jsx';
import * as client from './client.js';
import { debug } from './util.js';

const _ = cockpit.gettext;

Expand Down Expand Up @@ -276,6 +277,27 @@ class Application extends React.Component {
return new_wait;
}

/* lightweight version of updateContainer, but still needs the same serialization */
updateContainerState(id, system, props) {
const idx = id + system.toString();

if (!this.state.containers[idx])
// we got an event for a container which we didn't introspect yet
return this.updateContainer(id, system);

const wait = this.pendingUpdateContainer[idx] ?? Promise.resolve();

wait.then(() => this.setState(prevState => {
const containers = { ...prevState.containers };
const newContainer = { ...containers[idx], State: { ...containers[idx].State, ...props } };
containers[idx] = newContainer;
debug(system, "updateContainerState", idx, "to", JSON.stringify(newContainer.State));
return { containers };
}));
this.pendingUpdateContainer[idx] = wait;
wait.finally(() => { delete this.pendingUpdateContainer[idx] });
}

updateImage(id, system) {
client.getImages(system, id)
.then(reply => {
Expand Down Expand Up @@ -343,6 +365,15 @@ class Application extends React.Component {
case 'unmount':
case 'wait':
break;

/* The following events just change the State properties */
case 'pause':
this.updateContainerState(id, system, { Status: "paused" });
break;
case 'unpause':
this.updateContainerState(id, system, { Status: "running" });
break;

/* The following events need only to update the Container list
* We do get the container affected in the event object but for
* now we 'll do a batch update
Expand All @@ -353,17 +384,28 @@ class Application extends React.Component {
(event.Actor.Attributes.podId
? this.updatePod(event.Actor.Attributes.podId, system)
: this.updatePods(system)
).then(() => this.updateContainer(id, system, event));
).then(() => this.updateContainerState(
id, system,
{
Status: "running",
StartedAt: new Date(event.timeNano / 1000000).toISOString()
}));
break;
case 'checkpoint':

case 'died':
case 'stop':
this.updateContainerState(id, system, { Status: "stopped" });
break;

case 'cleanup':
// don't bother with setting FinishedAt, we don't use it anywhere
this.updateContainerState(id, system, { Status: "exited" });
break;

case 'checkpoint':
case 'create':
case 'died':
case 'exec_died': // HACK: pick up health check runs, see https://github.com/containers/podman/issues/19237
case 'pause':
case 'restore':
case 'stop':
case 'unpause':
case 'rename': // rename event is available starting podman v4.1; until then the container does not get refreshed after renaming
this.updateContainer(id, system, event);
break;
Expand Down
6 changes: 3 additions & 3 deletions test/check-application
Original file line number Diff line number Diff line change
Expand Up @@ -1235,10 +1235,10 @@ class TestApplication(testlib.MachineCase):
# Restart the container; there is no steady state change in the visible UI, so look for
# a changed data-started-at attribute
old_start = self.getStartTime("swamped-crate", auth=auth)
b.wait_in_text(f'#containers-containers tr[data-started-at="{old_start}"]', "swamped-crate")
old_start_dom = b.attr("#containers-containers tr[data-row-id", "data-started-at")
self.performContainerAction(IMG_BUSYBOX, "Force restart")
new_start = self.waitRestart("swamped-crate", old_start, auth=auth)
b.wait_in_text(f'#containers-containers tr[data-started-at="{new_start}"]', "swamped-crate")
self.waitRestart("swamped-crate", old_start, auth=auth)
b.wait_not_attr("#containers-containers tr[data-row-id", "data-started-at", old_start_dom)
self.waitContainer(container_sha, auth, name='swamped-crate', image=IMG_BUSYBOX, state='Running')

self.waitContainerRow(IMG_BUSYBOX)
Expand Down

0 comments on commit d3cb07d

Please sign in to comment.