處理已排定事件時,可使用準備與復原兩個主要元件。 所有影響 VM 的目前已排定事件,都能透過 IMDS 已排定事件端點進行讀取。 事件到達終止狀態時,就會從事件清單中移除。 下圖說明了單一已排定事件可能經歷的各種狀態轉換:
針對 EventStatus 為「已排程」狀態的事件,必須執行相關步驟以準備工作負載。 準備完成後,應使用已排定事件 API 來核准事件。 否則,一旦到達 NotBefore 時間,即會自動核准事件。 如果 VM 位於共用基礎結構上,系統則會等待相同硬體上的所有其他租用戶也核准作業或逾時。 一旦已從所有受影響的 VM 收集到核准,或已到達 NotBefore 時間,Azure 就會產生 EventStatus 為「已啟動」狀態的已排定事件承載,並觸發維護事件。 事件到達終止狀態時,就會從事件清單中移除。 這可做為客戶復原其 VM 的訊號。
以下虛擬碼示範了如何在應用程式中讀取和管理已排定事件:
current_list_of_scheduled_events = get_latest_from_se_endpoint()
#prepare for new events
for each event in current_list_of_scheduled_events:
if event not in previous_list_of_scheduled_events:
prepare_for_event(event)
#recover from completed events
for each event in previous_list_of_scheduled_events:
if event not in current_list_of_scheduled_events:
receover_from_event(event)
#prepare for future jobs
previous_list_of_scheduled_events = current_list_of_scheduled_events
{
"DocumentIncarnation": 1,
"Events": [
]
}
{
"DocumentIncarnation": 2,
"Events": [
{
"EventId": "C7061BAC-AFDC-4513-B24B-AA5F13A16123",
"EventStatus": "Scheduled",
"EventType": "Freeze",
"ResourceType": "VirtualMachine",
"Resources": [
"WestNO_0",
"WestNO_1"
],
"NotBefore": "Mon, 11 Apr 2022 22:26:58 GMT",
"Description": "Virtual machine is being paused because of a memory-preserving Live Migration operation.",
"EventSource": "Platform",
"DurationInSeconds": 5
}
]
}
{
"DocumentIncarnation": 3,
"Events": [
{
"EventId": "C7061BAC-AFDC-4513-B24B-AA5F13A16123",
"EventStatus": "Started",
"EventType": "Freeze",
"ResourceType": "VirtualMachine",
"Resources": [
"WestNO_0",
"WestNO_1"
],
"NotBefore": "",
"Description": "Virtual machine is being paused because of a memory-preserving Live Migration operation.",
"EventSource": "Platform",
"DurationInSeconds": 5
}
]
}
{
"DocumentIncarnation": 4,
"Events": [
]
}
Python 範例
下列範例會查詢中繼資料服務來找出已排定事件,並核准每個未處理的事件:
Python
#!/usr/bin/pythonimport json
import requests
from time import sleep
# The URL to access the metadata service
metadata_url ="http://169.254.169.254/metadata/scheduledevents"# This must be sent otherwise the request will be ignored
header = {'Metadata' : 'true'}
# Current version of the API
query_params = {'api-version':'2020-07-01'}
defget_scheduled_events():
resp = requests.get(metadata_url, headers = header, params = query_params)
data = resp.json()
return data
defconfirm_scheduled_event(event_id):# This payload confirms a single event with id event_id# You can confirm multiple events in a single request if needed
payload = json.dumps({"StartRequests": [{"EventId": event_id }]})
response = requests.post(metadata_url,
headers= header,
params = query_params,
data = payload)
return response.status_code
deflog(event):# This is an optional placeholder for logging events to your system
print(event["Description"])
returndefadvanced_sample(last_document_incarnation):# Poll every second to see if there are new scheduled events to process# Since some events may have necessarily short warning periods, it is # recommended to poll frequently
found_document_incarnation = last_document_incarnation
while (last_document_incarnation == found_document_incarnation):
sleep(1)
payload = get_scheduled_events()
found_document_incarnation = payload["DocumentIncarnation"]
# We recommend processing all events in a document together, # even if you won't be actioning on them right awayfor event in payload["Events"]:
# Events that have already started, logged for trackingif (event["EventStatus"] == "Started"):
log(event)
# Approve all user initiated events. These are typically created by an # administrator and approving them immediately can help to avoid delays # in admin actionselif (event["EventSource"] == "User"):
confirm_scheduled_event(event["EventId"])
# For this application, freeze events less that 9 seconds are considered# no impact. This will immediately approve themelif (event["EventType"] == "Freeze"and
int(event["DurationInSeconds"]) >= 0and
int(event["DurationInSeconds"]) < 9):
confirm_scheduled_event(event["EventId"])
# Events that may be impactful (for example, reboot or redeploy) may need custom # handling for your applicationelse:
#TODO Custom handling for impactful events
log(event)
print("Processed events from document: " + str(found_document_incarnation))
return found_document_incarnation
defmain():# This will track the last set of events seen
last_document_incarnation = "-1"
input_text = "\
Press 1 to poll for new events \n\
Press 2 to exit \n "
program_exit = Falsewhile program_exit == False:
user_input = input(input_text)
if (user_input == "1"):
last_document_incarnation = advanced_sample(last_document_incarnation)
elif (user_input == "2"):
program_exit = Trueif __name__ == '__main__':
main()