Due to network latency, I recommend the following design for miners:
1. getwork, record <duration of getwork request> and <time+getwork expire> , and begin mining on it
2. every second, update ntime and reset nonce to <first nonce>
3. when a share is found, submit it. record the duration of the submit request.
4. if a share submission fails due to a network error, save the share and retry it a second later the same as step 3; also immediately (regardless of how long the current work has been active) begin trying to get new work (which is treated the same as step 5+6 when done)
5. when current time is past <time@1+getwork expire> minus <duration of longest getwork/submit since we started this work> times 4, begin a request for new work
6. when new work arrives, discard old work and begin using the new work.
If I understand this correctly, rather than waiting until the exact getwork expire deadline, you are getting new work a little bit early, based on how long the getwork/submit request takes? So for example if getwork takes at most 5 seconds you get new work 20 seconds before the current work expires, to avoid submitting expired shares.
What about just a fixed percentage or a fixed duration? I might worry that this scheme could have unintended side-effects. If server load increases lagginess, it could be self-reinforcing if it increases the chances that the miners will decide to refresh their work. What might have been randomly spread out over time could become concentrated and bursty. I am visualizing sand dunes but I can't connect it with words.