Retrying Is Not Another Reasoning Step
Chapter III guarantees a limited number of calls, but a failure to re-call may result in duplication. Defines the business intent to set aside a certain quantity of equipment for a mission; attempts are an opportunity to transmit or execute the intention; and results are real deductions from inventory. An attempt can be made several times, but correct agreements like this make it possible to produce the same effect at most once. Reading documents is usually not written in stock, while setting asides are available, so that all tools cannot be given a non-differentiated “Try again after the hour.”. This chapter discusses only current local single database matters and does not commit remote services automatically once.
The client may have been successful for several reasons: the request has not been executed, the execution has failed and rolls back, the transaction has been submitted but the response has been lost, the response has arrived but the client has not been able to save it. Both the latter and the first two can be shown to be inconclusive. “If you catch an anomaly, you'll have to do it again.” is therefore not a recovery strategy. The project's lost_reply malfunctions were dropped after the inventory and return had been submitted, and crash_affer_committees were interrupted by direct simulations to keep the feeding in a sustainable state; Both were generated through actual database changes, not by hand-written failure messages.
Idempotency Keys Bind Business Intent
The project generates keys such as task id, device id, and quantity-modified summaries. The same pending retry must retain the original key and complete parameters, without creating new keys by random numbers at each attempt. The tool end book uses the key, while preserving the fingerprint and result of the parameter. If the key already exists and the fingerprint is identical, then the result is returned directly; if the key corresponds to different parameters, the conflict is rejected. This avoids the caller 's misusing the key to disguise the request for a single number two as a previous number one success. The key is not a secret or an authorized instrument, and the executor authorization is still executed first.
The parameter fingerprint contains the expected inventory version. The version is used for optimism and checking: when you read three versions available, version zero, only the current version will be implemented when it is zero. Another matter has been changed to version one, and the old version request fails and cannot continue quietly in the new state. A valid re-test of the same business key is checked first and returned to the original, so even if the current version is one, it will be successful; if a copy check is put to the account book, it will be wrongly misjudged as having expired its successful re-test. This order is part of the protocol.
Why Effects and Receipts Must Share a Transaction
If the inventory is first withheld and then retained, the intermediate collapse will have the effect but not the key, and it will again be held again. If the inventory is successfully returned, the intermediate crash will leave “Success” unattained. The project will update the inventory and feeder into the same SQLite service: both are visible when submitted, and the exception will roll back. This local atom is derived from the mechanism of the database and its documentation system, and the course will use it as an import capability described in the official document and will not reprove the disk atomic submission algorithm. The application still ensures that both articles are actually included in the same matter.
Client saving observed is not the same thing as tool-end services: tools are submitted and returned, and Runner then saves observations. There are still windows in the middle, but the syllables allow retry to read the submitted results and complete the client. This local technique cannot automatically extend to remote effects if the remote mail or payment interface does not support the key. At that time, protocols such as business status, manual reconciliation, compensation, or service-end clarity need to be checked.
Worked Example 1: A Lost Reply with a Single Inventory Deduction
Camera starts with three versions and zeroes. The first reserve is executed with k, volume one, the inventory is changed to two, version one, the account book is written into the result r, and the failed response is lost. Runner has recorded a fourth attempt, but the options are still not available. The next attempt is to find k, the parameter fingerprints are identical, return to the same r, no more inventory. Eventually, the calls are five, two of which try the same reserve; Only one of them, the inventory is still two. If you look at the calls alone, you will miss the cost of recovery if you look only at the successful text.
The recovery that was interrupted after submission was also the same. After closing and reopening the database, the event replay confirmed that thepending is still in place, with the next attempt to hit the same key into the account book and complete observation and closure. Test actual disconnection and recovery with a new Runner, check the calls, inventory, ledger and final state. “One effect at most” is set up within the same key and local database; not all attempts are successful, and budget or permanent errors may not be completed. Restoring reliability requires both safety and completion conditions.
import sqlite3
con=sqlite3.connect(':memory:')
con.executescript('CREATE TABLE stock(n INTEGER);INSERT INTO stock VALUES(3);CREATE TABLE receipts(k TEXT PRIMARY KEY,n INTEGER);')
def reserve(key,qty):
with con:
old=con.execute('SELECT n FROM receipts WHERE k=?',(key,)).fetchone()
if old:
if old[0]!=qty:raise ValueError('payload conflict')
return
con.execute('UPDATE stock SET n=n-?',(qty,))
con.execute('INSERT INTO receipts VALUES(?,?)',(key,qty))
reserve('same',1);reserve('same',1)
assert con.execute('SELECT n FROM stock').fetchone()[0]==2
try:reserve('same',2)
except ValueError:pass
else:raise AssertionError('conflict accepted')
assert con.execute('SELECT n FROM stock').fetchone()[0]==2
con.close();print('one effect, repeated delivery PASS')Worked Example 2: Exhausted Retries May Still Have Produced Side Effects
Change the number of permitted retries in the same lost_reply situation to zero. The first request has been submitted for stock two and return, but the client has terminated the request_exhausted, observations as soon as it receives an anomaly. If the report interprets this termination status as “no reserve, so a new request can be sent directly”, the new key will be withheld again. The fixed task of the project is lost-reply-no-retry expected retry_exhausted; it is a deliberately reserved unknown confirmed boundary. Client failure and business effectiveness are priced at zero.
See also the same charge conflict: K-keys first reserved a camera and then changed the number two by the same key. Tools should be rejected without returning the old results as a success for this time, and no new quantities should be executed. Independent testing of inventories is still two. If new keys are changed but the old version is zero, it should also be rejected because the version is outdated. The two sources of refusal are different: the former protects identity consistency and the latter protects the status prerequisite. The error log should retain the conflict type, so that the caller knows whether to restore consent to the map or read it again and build a new business decision.
Which Errors Can Be Retried?
Current TransientError is used only for temporary failure and loss of response to a specified injection; Contractor Error means unknown object, parameter conflict, expired version or stock is insufficient and does not automatically retry. Retrying must maintain the feed, add attachments and calls, and be bound by both ceilings. The project has no actual delay or index retreat because it disappears one step after the offline malfunction; Real network systems often need to retreat and shake to avoid convulsions at the same time, but this is load control and requires actual time and flow of evidence that cannot be forged here.
The error classification itself should be cautious. Overtime does not prove that the service has not been performed, so non-scrambling writing cannot be done only with the “Temporary Error” label security. Conversely, a clear parameter validation failure will not automatically legalize over time and repeated attempts will cost only the budget. If there is a cancellation, the client cancellation will not mean that the remote transaction has been cancelled; it should be sustained and Queryed. The course opens these seemingly synonym “Failed” to allow recovery strategies to be determined by status and evidence rather than by emotional retesting.
The first category is duplicate delivery variable: the same parameters are repeated randomly, and the inventory changes only once and returns the same. The second category is downtime: temporary failure prior to execution, submission of a response, interruption after submission, non-repeated test amounts produce the expected state and effect respectively. Tests such as tweaks are not available to cover real dangerous windows only when normal success is requested. The current 17 fixed tasks and 16 module inspections contain these representative boundaries, without the multiple process grabs, distribution of two phases or infinite history keys.
The book retention period is also part of the agreement. The current teaching database is permanently maintained and not cleared; if the production system deletes its reply after one day, the same old request may be re-arrival. “Console at most.” therefore has the corresponding assurance only for the period during which the key remains valid. Extensions should specify the only range of life cycle conditions to which the request will be valid, retain, be late for processing and task identity, without a summary field.
Exercises and Project Contributions
TRY IT YOURSELF
Base: three counts
The first submission of a business intent has failed, and the second key has been successfully read and returned.
Hint 1
Hint 2
Compare with the Solution
TRY IT YOURSELF
Step: Error order of events
Write back and withhold stocks. Why is it not safe? Give me a breakout.
Hint 1
Hint 2
Compare with the Solution
TRY IT YOURSELF
Challenge: Unknown outcome processing
Can retry_exhausted prove that the inventory has not been changed?
Hint 1
Hint 2
Compare with the Solution
This chapter increases the result of a ledger, a fingerprint of parameters, an expired version check and a failure to connect after submission. The next chapter examines the dangerous input of tools and information; even if it is correct, a single error will occur if the attacker can insert another permission action into the executor.
BUILD THE MECHANISM
Complete execution, retry and crash recovery
The same LearnerRunner.step achieves a prepared platte tool observed using the existing Store atomic service. Downloads this full course item, running in the project root directory; edits only learner/starter.py, which already has a tectonic framework provided by the project. The check at this stage is returned to reserve tool observation and remains running; The final reference is left to the subsequent phase of event and does not require pre-filling of validate_claims.
Input and Output Prepared saves first and failed tool calls also charge; pending is empty only after the results have been observed.
Collapse after submission to recover with key; stock withdrawal at most once; retest consumption submitted to the extent possible.
# LearnerRunner.step(替换已提供类的此方法)
def step(self,state,fault=None):
raise NotImplementedError('execute')Hint 1
Draws the intermediate state by distinguishing between service endcommittee and client endobserved.
Hint 2
Saves pending and attachment_started before execute, with action and key on recovery.
Hint 3
The real temporary SQLite manufacture has been carried out only on the basis of a cross_affer_committee; the inventory should be kept in one row and the ledger should have only one row.
Independent inspection python3 -m learner.check --stage execute --output runs/learner-execute.json
Migration test With new equipment and quantity=2 Repeated submissions are interrupted; the number of submissions is reported separately from the number of calls made by the client.
Reference Implementation and Explanation
# LearnerRunner.step(替换已提供类的此方法)
def step(self,state,fault=None):
if state['status']!='running':return state
if state['pending'] is None:
try:
action=validate_action(self.policy.next_action(copy.deepcopy(state)))
self.authorize(state,action)
if action['kind']=='finish':return self.finalize(state,action['status'])
if state['calls']>=state['task']['max_calls']:
state['status']='budget_exhausted';self.store.save(state,'budget_exhausted');return state
except (ContractError,ValueError,KeyError,TypeError,OSError) as error:
state['status']='policy_error';state['result']={'error':str(error)};self.store.save(state,'policy_error');return state
state['pending']=action;state['attempts']=0;state['decisions']+=1
self.store.save(state,'prepared')
if state['calls']>=state['task']['max_calls']:
state['status']='budget_exhausted';self.store.save(state,'budget_exhausted');return state
state['calls']+=1;state['attempts']+=1;self.store.save(state,'attempt_started')
try:
self.authorize(state,state['pending']);result=self.store.execute(state['pending'],fault)
except TransientError as error:
if state['attempts']>state['task']['max_retries']:state['status']='retry_exhausted'
self.store.save(state,'transient:'+str(error));return state
except ContractError as error:
state['status']='tool_error';state['result']={'error':str(error)};self.store.save(state,'tool_error');return state
state['observations'][state['pending']['name']]=result;state['pending']=None
self.store.save(state,'observed');return state