File

FILE: projects/scheduler_v2_adapter.py
SIZE: 3677 bytes
SHA256: 3e41d05d03e607082581f738865eefa1f5e74ff680229d3495c0604be08b3dcc
Lines: 70

Use path as FILE | Patch Context | Read first 100 | Read prev 100 | Read next 100 | Git diff this file | Code Buffers | Active Patch Context

Blocks / Symbols (python)

LineTextActions
1
import datetime as dt
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
2
import json
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
3
try:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
4
    from .scheduler_v2 import Client, Command, Scheduler
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
5
except ImportError:  # Supports running this file directly from projects/.
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
6
    from scheduler_v2 import Client, Command, Scheduler
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
7
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
8
REVISION='20260902-01-ADAPTER-SHADOW'
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
9
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
10
def parse_clients(rows):
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
11
    out={}
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
12
    for r in rows:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
13
        if not r or len(r) < 10 or not r[0] or str(r[9]).upper()!='TRUE':
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
14
            continue
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
15
        try:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
16
            weight = max(1, int(r[1] or 1))
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
17
            max_inflight = max(1, int(r[3] or 1))
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
18
        except (TypeError, ValueError):
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
19
            continue
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
20
        out[str(r[0])]=Client(str(r[0]), weight, max_inflight)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
21
    return out
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
22
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
23
def parse_commands(rows):
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
24
    out=[]
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
25
    for r in rows:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
26
        if not r or not r[0]:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
27
            continue
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
28
        if len(r) < 16:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
29
            continue
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
30
        try:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
31
            keys=tuple(str(item) for item in json.loads(r[5] or '[]'))
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
32
            created=dt.datetime.fromisoformat(str(r[3]).replace('Z','+00:00'))
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
33
            if created.tzinfo is None:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
34
                created=created.replace(tzinfo=dt.timezone.utc)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
35
            priority=int(r[4] or 50)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
36
            ttl=max(1, int(r[13] or 300))
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
37
        except (TypeError, ValueError, json.JSONDecodeError):
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
38
            continue
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
39
        out.append(Command(
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
40
            command_id=str(r[0]), client_id=str(r[1]), seq=int(r[2] or 0),
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
41
            created_at=created, priority=priority, resource_keys=keys,
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
42
            action=str(r[6] or 'health'), payload_json=str(r[7] or '{}'),
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
43
            status=str(r[8] or 'pending'), ttl_seconds=ttl,
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
44
            supersedes_command_id=str(r[14] or ''), coalesce_key=str(r[15] or ''),
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
45
        ))
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
46
    return out
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
47
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
48
def shadow_plan(client_rows,command_rows,max_workers=3,now=None):
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
49
    now=now or dt.datetime.now(dt.timezone.utc)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
50
    s=Scheduler(parse_clients(client_rows),60,30)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
51
    cmds=parse_commands(command_rows)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
52
    selected=[]
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
53
    for _ in range(max_workers):
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
54
        c=s.choose(cmds,now)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
55
        if not c: break
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
56
        token,until=s.acquire(c,now)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
57
        selected.append({'command_id':c.command_id,'client_id':c.client_id,'resources':list(c.resource_keys),'fence_token':token,'lease_until':until.isoformat()})
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
58
        c.status='shadow_selected'
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
59
    return {'ok':True,'revision':REVISION,'execution_enabled':False,'selected':selected,'states':{c.command_id:c.status for c in cmds}}
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
60
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
61
def self_test():
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
62
    clients=[['chatgpt-main','2','100','2','0','0','0','','','TRUE'],['chatgpt-work','1','80','1','0','0','0','','','TRUE'],['codex','1','70','2','0','0','0','','','TRUE'],['other-llm','1','50','1','0','0','0','','','TRUE']]
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
63
    commands=[['v2test-main-1','chatgpt-main','1','2026-09-02T11:27:00Z','50','[\"apps-script\"]','status','{}','pending','yes','','','','300','','apps-status'],['v2test-main-2','chatgpt-main','2','2026-09-02T11:27:01Z','50','[\"apps-script\"]','status','{}','pending','yes','','','','300','','apps-status'],['v2test-work-1','chatgpt-work','1','2026-09-02T11:27:02Z','100','[\"android-build\"]','health','{}','pending','yes','','','','300','',''],['v2test-codex-1','codex','1','2026-09-02T11:20:00Z','20','[\"apps-script\"]','job_status','{}','pending','yes','','','','60','',''],['v2test-other-1','other-llm','1','2026-09-02T11:27:03Z','50','[\"file:project/x\"]','git_status','{}','pending','yes','','','','300','','git-x']]
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
64
    out=shadow_plan(clients,commands,3,dt.datetime.fromisoformat('2026-09-02T11:28:00+00:00'))
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
65
    assert out['states']['v2test-main-1']=='superseded'
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
66
    assert out['states']['v2test-codex-1']=='expired'
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
67
    assert out['execution_enabled'] is False
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
68
    print(json.dumps(out,separators=(',',':')))
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
69
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
70
if __name__=='__main__': self_test()
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A