zilencer: Update last_audit_log_update before `sync_license_ledger..`.

We need to update 'last_audit_log_update' before calling the
'sync_license_ledger_if_needed' method to avoid 'MissingDataError'
due to 'has_stale_audit_log' being True.

Also, we made the code block that creates audit logs,
updates 'last_audit_log_update', and syncs LicenseLedger in
an atomic operation.

This helps to rely on 'last_audit_log_update' to assume
'RemoteRealmAuditLog' and 'LicenseLedger' are up-to-date.
This commit is contained in:
Prakhar Pratyush 2023-12-12 15:17:06 +05:30 committed by Tim Abbott
parent cae11a60b6
commit 88fe0a7561
1 changed files with 45 additions and 39 deletions

View File

@ -925,48 +925,54 @@ def remote_server_post_analytics(
batch_create_table_data(server, RemoteInstallationCount, remote_installation_counts) batch_create_table_data(server, RemoteInstallationCount, remote_installation_counts)
if realmauditlog_rows is not None: if realmauditlog_rows is not None:
# Important: Do not return early if we receive 0 rows; we must # Creating audit logs, syncing license ledger, and updating
# updated last_audit_log_update even if there are no new rows, # 'last_audit_log_update' needs to be an atomic operation.
# to help identify server whose ability to connect to this # This helps to rely on 'last_audit_log_update' to assume
# endpoint is broken by a networking problem. # RemoteRealmAuditLog and LicenseLedger are up-to-date.
remote_realms_set = set() with transaction.atomic():
remote_realm_audit_logs = [] # Important: Do not return early if we receive 0 rows; we must
for row in realmauditlog_rows: # updated last_audit_log_update even if there are no new rows,
extra_data = {} # to help identify server whose ability to connect to this
if isinstance(row.extra_data, str): # endpoint is broken by a networking problem.
try: remote_realms_set = set()
extra_data = orjson.loads(row.extra_data) remote_realm_audit_logs = []
except orjson.JSONDecodeError: for row in realmauditlog_rows:
raise JsonableError(_("Malformed audit log data")) extra_data = {}
elif row.extra_data is not None: if isinstance(row.extra_data, str):
assert isinstance(row.extra_data, dict) try:
extra_data = row.extra_data extra_data = orjson.loads(row.extra_data)
remote_realms_set.add(realm_id_to_remote_realm.get(row.realm)) except orjson.JSONDecodeError:
remote_realm_audit_logs.append( raise JsonableError(_("Malformed audit log data"))
RemoteRealmAuditLog( elif row.extra_data is not None:
remote_realm=realm_id_to_remote_realm.get(row.realm), assert isinstance(row.extra_data, dict)
realm_id=row.realm, extra_data = row.extra_data
remote_id=row.id, remote_realms_set.add(realm_id_to_remote_realm.get(row.realm))
server=server, remote_realm_audit_logs.append(
event_time=datetime.fromtimestamp(row.event_time, tz=timezone.utc), RemoteRealmAuditLog(
backfilled=row.backfilled, remote_realm=realm_id_to_remote_realm.get(row.realm),
extra_data=extra_data, realm_id=row.realm,
event_type=row.event_type, remote_id=row.id,
server=server,
event_time=datetime.fromtimestamp(row.event_time, tz=timezone.utc),
backfilled=row.backfilled,
extra_data=extra_data,
event_type=row.event_type,
)
) )
batch_create_table_data(server, RemoteRealmAuditLog, remote_realm_audit_logs)
# We need to update 'last_audit_log_update' before calling the
# 'sync_license_ledger_if_needed' method to avoid 'MissingDataError'
# due to 'has_stale_audit_log' being True.
RemoteZulipServer.objects.filter(uuid=server.uuid).update(
last_audit_log_update=timezone_now()
) )
batch_create_table_data(server, RemoteRealmAuditLog, remote_realm_audit_logs)
# Update LicenseLedger using logs in RemoteRealmAuditlog. # Update LicenseLedger using logs in RemoteRealmAuditlog.
for remote_realm in remote_realms_set: for remote_realm in remote_realms_set:
if remote_realm: if remote_realm:
billing_session = RemoteRealmBillingSession(remote_realm=remote_realm) billing_session = RemoteRealmBillingSession(remote_realm=remote_realm)
billing_session.sync_license_ledger_if_needed() billing_session.sync_license_ledger_if_needed()
# Do this last, so we can assume LicenseLedger is always
# up-to-date through last_audit_log_update.
RemoteZulipServer.objects.filter(uuid=server.uuid).update(
last_audit_log_update=timezone_now()
)
remote_realm_dict: Dict[str, RemoteRealmDictValue] = {} remote_realm_dict: Dict[str, RemoteRealmDictValue] = {}
remote_realms = RemoteRealm.objects.filter(server=server) remote_realms = RemoteRealm.objects.filter(server=server)