Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Add transactional API to history purge #2962

Merged
merged 2 commits into from
Mar 12, 2018
Merged

Conversation

richvdh
Copy link
Member

@richvdh richvdh commented Mar 8, 2018

Make the purge request return quickly, and allow scripts to poll for updates.

(includes #2961)

@richvdh
Copy link
Member Author

richvdh commented Mar 8, 2018

retest this please

@richvdh
Copy link
Member Author

richvdh commented Mar 8, 2018

remaining test failure is because the test was broken (now fixed) and PR builder doesn't rerun the commit tests

Copy link
Member

@erikjohnston erikjohnston left a comment

Choose a reason for hiding this comment

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

Broadly LGTM, I've commented on a lot of nits, most of which are just opinions so shrug. Could do with a couple of docstrings and s/error/failed/ in the docs though.

self._purges_in_progress_by_room.add(room_id)
try:
with (yield self.pagination_lock.write(room_id)):
yield self.store.purge_history(
room_id, topological_ordering, delete_local_events,
)
logger.info("[purge] complete")
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we should log the purge_id too for all these log lines. Maybe set the request_id for the context or something?>

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah could do. Or we could make sure we log the purge id against the existing request_id so that you could tie the log lines together through that?

Copy link
Member

Choose a reason for hiding this comment

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

Yup, happy either way.

Copy link
Member Author

Choose a reason for hiding this comment

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

ok, changed to log the purge_id

logger.info("[purge] complete")
self._purges_by_id[purge_id].status = "complete"
except Exception:
logger.error("[purge] failed: %s", Failure().getTraceback().rstrip())
Copy link
Member

Choose a reason for hiding this comment

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

Why are we not logging as an exception?

Copy link
Member Author

Choose a reason for hiding this comment

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

what do you mean, and why would we do so?

Copy link
Member

Choose a reason for hiding this comment

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

As in, why aren't we using logger.exception(...) rather than manually building a stack trace?

Copy link
Member Author

Choose a reason for hiding this comment

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

ah right. Because Failure().getTraceback() will give us the proper stacktrace, whereas sys.exc_info (and hence logger.exception) get confused by the deferreds and only go one frame down.

finally:
self._purges_in_progress_by_room.discard(room_id)

# remove the purge from the list an hour after it completes
def clear_purge():
del self._purges_by_id[purge_id]
Copy link
Member

Choose a reason for hiding this comment

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

For paranoia's sake I tend to prefer d.pop(key, None), as that won't throw if the key doesn't exist, but shrug.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'd argue that knowing the key has gone missing would be a good thing...

Copy link
Member

Choose a reason for hiding this comment

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

fair

self.status = "active"

def asdict(self):
return self.__dict__
Copy link
Member

Choose a reason for hiding this comment

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

I'm not entirely convinced this is better than just using a regular dict. Having a dedicated PurgeStatus class is useful for documenting and enforcing the return values, but I don't think that this particular construct really does either of those.

I'd prefer either a subclass of namedtuple (it does helpfully provide an _asdict already), or have asdict be explicit about the properties it returns, i.e. {"status": self.status}

Copy link
Member

Choose a reason for hiding this comment

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

Also, a short docstring would be good.

Copy link
Member Author

Choose a reason for hiding this comment

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

I tried a namedtuple to start with, but I wanted the individual fields to be mutable so that didn't work.

So yes, I can make it a more explicit dict.

Copy link
Member

Choose a reason for hiding this comment

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

I tried a namedtuple to start with, but I wanted the individual fields to be mutable so that didn't work.

Ah, of course.

Copy link
Member Author

Choose a reason for hiding this comment

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

have made asdict more explicit, and turned status into a more enummy thing while I'm at it

def purge_history(self, room_id, topological_ordering,
delete_local_events=False):
def start_purge_history(self, room_id, topological_ordering,
delete_local_events=False):
if room_id in self._purges_in_progress_by_room:
Copy link
Member

Choose a reason for hiding this comment

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

Docstring?

Copy link
Member Author

Choose a reason for hiding this comment

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

done

# remove the purge from the list an hour after it completes
def clear_purge():
del self._purges_by_id[purge_id]
reactor.callLater(3600, clear_purge)
Copy link
Member

Choose a reason for hiding this comment

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

Given this can take hours, I'd probably have it much higher, like 24hours or something

Copy link
Member Author

Choose a reason for hiding this comment

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

the logic went that if you were polling, you'd get what you needed within an hour either way. Can change it to 24h if you like though...

Copy link
Member

Choose a reason for hiding this comment

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

I was just thinking in terms of people manually curling. Given how small PurgeStatus is I think we may as well keep them for longer.

Copy link
Member Author

Choose a reason for hiding this comment

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

done


purge_status = self.handlers.message_handler.get_purge_status(purge_id)
if purge_status is None:
raise NotFoundError("purge id '%s' not found" % purge_id)
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if it'd be better to merge completed status with an unknown token status, so that even if we remove the entry we get the same result?

Copy link
Member Author

Choose a reason for hiding this comment

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

wat

Copy link
Member

Choose a reason for hiding this comment

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

Currently a 404 means that either the token was invalid or the purge has completed but we've forgotten the ID.... Oh, I guess that's not true if we restart half way through. Nevermind.

"status": "active"
}

The status will be one of ``active``, ``complete``, or ``error``.
Copy link
Member

Choose a reason for hiding this comment

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

We return failed not error

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed, thanks


# we log the purge_id here so that it can be tied back to the
# request id in the log lines.
logger.info("[purge] starting purge_id %s" % purge_id)
Copy link
Member

Choose a reason for hiding this comment

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

Should be logger.info("...", purge_id)

Copy link
Member

@erikjohnston erikjohnston left a comment

Choose a reason for hiding this comment

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

Other than using % inside a logger.info, LGTM

richvdh added 2 commits March 12, 2018 16:22
Queuing up purges doesn't sound like a good thing.
Make the purge request return quickly, and allow scripts to poll for updates.
@richvdh richvdh force-pushed the rav/purge_history_txns branch from 0695257 to e48c7aa Compare March 12, 2018 16:23
@richvdh richvdh merged commit d65ceb4 into develop Mar 12, 2018
@richvdh richvdh deleted the rav/purge_history_txns branch March 12, 2018 16:34
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants