netrender: first draft for job balancer + some minor fixes

This commit is contained in:
Martin Poirier 2009-09-19 22:11:26 +00:00
parent 8b4ad3584c
commit b28109b442
8 changed files with 135 additions and 52 deletions

@ -6,6 +6,7 @@ import client
import slave import slave
import master import master
import utils import utils
import balancing
import ui import ui
# store temp data in bpy module # store temp data in bpy module

@ -0,0 +1,75 @@
import time
from netrender.utils import *
import netrender.model
class RatingRule:
def rate(self, job):
return 0
class ExclusionRule:
def test(self, job):
return False
class PriorityRule:
def test(self, job):
return False
class Balancer:
def __init__(self):
self.rules = []
self.priorities = []
self.exceptions = []
def addRule(self, rule):
self.rules.append(rule)
def addPriority(self, priority):
self.priorities.append(priority)
def addException(self, exception):
self.exceptions.append(exception)
def applyRules(self, job):
return sum((rule.rate(job) for rule in self.rules))
def applyPriorities(self, job):
for priority in self.priorities:
if priority.test(job):
return True # priorities are first
return False
def applyExceptions(self, job):
for exception in self.exceptions:
if exception.test(job):
return True # exceptions are last
return False
def sortKey(self, job):
return (1 if self.applyExceptions(job) else 0, # exceptions after
0 if self.applyPriorities(job) else 1, # priorities first
self.applyRules(job))
def balance(self, jobs):
if jobs:
jobs.sort(key=self.sortKey)
return jobs[0]
else:
return None
# ==========================
class RatingCredit(RatingRule):
def rate(self, job):
return -job.credits # more credit is better (sort at first in list)
class NewJobPriority(PriorityRule):
def test(self, job):
return job.countFrames(status = DISPATCHED) == 0
class ExcludeQueuedEmptyJob(ExclusionRule):
def test(self, job):
return job.status != JOB_QUEUED or job.countFrames(status = QUEUED) == 0

@ -103,7 +103,7 @@ def clientSendJob(conn, scene, anim = False, chunks = 5):
job.priority = netsettings.priority job.priority = netsettings.priority
# try to send path first # try to send path first
conn.request("POST", "job", repr(job.serialize())) conn.request("POST", "/job", repr(job.serialize()))
response = conn.getresponse() response = conn.getresponse()
job_id = response.getheader("job-id") job_id = response.getheader("job-id")
@ -112,7 +112,7 @@ def clientSendJob(conn, scene, anim = False, chunks = 5):
if response.status == http.client.ACCEPTED: if response.status == http.client.ACCEPTED:
for filepath, start, end in job.files: for filepath, start, end in job.files:
f = open(filepath, "rb") f = open(filepath, "rb")
conn.request("PUT", "file", f, headers={"job-id": job_id, "job-file": filepath}) conn.request("PUT", "/file", f, headers={"job-id": job_id, "job-file": filepath})
f.close() f.close()
response = conn.getresponse() response = conn.getresponse()
@ -121,7 +121,7 @@ def clientSendJob(conn, scene, anim = False, chunks = 5):
return job_id return job_id
def requestResult(conn, job_id, frame): def requestResult(conn, job_id, frame):
conn.request("GET", "render", headers={"job-id": job_id, "job-frame":str(frame)}) conn.request("GET", "/render", headers={"job-id": job_id, "job-frame":str(frame)})
@rnaType @rnaType
class NetworkRenderEngine(bpy.types.RenderEngine): class NetworkRenderEngine(bpy.types.RenderEngine):
@ -174,7 +174,6 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
requestResult(conn, job_id, scene.current_frame) requestResult(conn, job_id, scene.current_frame)
while response.status == http.client.ACCEPTED and not self.test_break(): while response.status == http.client.ACCEPTED and not self.test_break():
print("waiting")
time.sleep(1) time.sleep(1)
requestResult(conn, job_id, scene.current_frame) requestResult(conn, job_id, scene.current_frame)
response = conn.getresponse() response = conn.getresponse()

@ -4,10 +4,7 @@ import subprocess, shutil, time, hashlib
from netrender.utils import * from netrender.utils import *
import netrender.model import netrender.model
import netrender.balancing
JOB_WAITING = 0 # before all data has been entered
JOB_PAUSED = 1 # paused by user
JOB_QUEUED = 2 # ready to be dispatched
class MRenderFile: class MRenderFile:
def __init__(self, filepath, start, end): def __init__(self, filepath, start, end):
@ -38,10 +35,6 @@ class MRenderSlave(netrender.model.RenderSlave):
def seen(self): def seen(self):
self.last_seen = time.time() self.last_seen = time.time()
# sorting key for jobs
def groupKey(job):
return (job.status, job.framesLeft() > 0, job.priority, job.credits)
class MRenderJob(netrender.model.RenderJob): class MRenderJob(netrender.model.RenderJob):
def __init__(self, job_id, name, files, chunks = 1, priority = 1, credits = 100.0, blacklist = []): def __init__(self, job_id, name, files, chunks = 1, priority = 1, credits = 100.0, blacklist = []):
super().__init__() super().__init__()
@ -96,14 +89,6 @@ class MRenderJob(netrender.model.RenderJob):
self.frames.append(frame) self.frames.append(frame)
return frame return frame
def framesLeft(self):
total = 0
for j in self.frames:
if j.status == QUEUED:
total += 1
return total
def reset(self, all): def reset(self, all):
for f in self.frames: for f in self.frames:
f.reset(all) f.reset(all)
@ -153,7 +138,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
def do_HEAD(self): def do_HEAD(self):
print(self.path) print(self.path)
if self.path == "status": if self.path == "/status":
job_id = self.headers.get('job-id', "") job_id = self.headers.get('job-id', "")
job_frame = int(self.headers.get('job-frame', -1)) job_frame = int(self.headers.get('job-frame', -1))
@ -185,12 +170,12 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
def do_GET(self): def do_GET(self):
print(self.path) print(self.path)
if self.path == "version": if self.path == "/version":
self.send_head() self.send_head()
self.server.stats("", "New client connection") self.server.stats("", "New client connection")
self.wfile.write(VERSION) self.wfile.write(VERSION)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "render": elif self.path == "/render":
job_id = self.headers['job-id'] job_id = self.headers['job-id']
job_frame = int(self.headers['job-frame']) job_frame = int(self.headers['job-frame'])
print("render:", job_id, job_frame) print("render:", job_id, job_frame)
@ -221,7 +206,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
# no such job id # no such job id
self.send_head(http.client.NO_CONTENT) self.send_head(http.client.NO_CONTENT)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "log": elif self.path == "/log":
job_id = self.headers['job-id'] job_id = self.headers['job-id']
job_frame = int(self.headers['job-frame']) job_frame = int(self.headers['job-frame'])
print("log:", job_id, job_frame) print("log:", job_id, job_frame)
@ -250,7 +235,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
# no such job id # no such job id
self.send_head(http.client.NO_CONTENT) self.send_head(http.client.NO_CONTENT)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "status": elif self.path == "/status":
job_id = self.headers.get('job-id', "") job_id = self.headers.get('job-id', "")
job_frame = int(self.headers.get('job-frame', -1)) job_frame = int(self.headers.get('job-frame', -1))
@ -284,7 +269,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
self.wfile.write(bytes(repr(message), encoding='utf8')) self.wfile.write(bytes(repr(message), encoding='utf8'))
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "job": elif self.path == "/job":
self.server.update() self.server.update()
slave_id = self.headers['slave-id'] slave_id = self.headers['slave-id']
@ -315,7 +300,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
else: # invalid slave id else: # invalid slave id
self.send_head(http.client.NO_CONTENT) self.send_head(http.client.NO_CONTENT)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "file": elif self.path == "/file":
slave_id = self.headers['slave-id'] slave_id = self.headers['slave-id']
slave = self.server.updateSlave(slave_id) slave = self.server.updateSlave(slave_id)
@ -348,7 +333,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
else: # invalid slave id else: # invalid slave id
self.send_head(http.client.NO_CONTENT) self.send_head(http.client.NO_CONTENT)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "slave": elif self.path == "/slave":
message = [] message = []
for slave in self.server.slaves: for slave in self.server.slaves:
@ -368,7 +353,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
print(self.path) print(self.path)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
if self.path == "job": if self.path == "/job":
print("posting job info") print("posting job info")
self.server.stats("", "Receiving job") self.server.stats("", "Receiving job")
@ -394,7 +379,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
else: else:
self.send_head(http.client.ACCEPTED, headers=headers) self.send_head(http.client.ACCEPTED, headers=headers)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "cancel": elif self.path == "/cancel":
job_id = self.headers.get('job-id', "") job_id = self.headers.get('job-id', "")
if job_id: if job_id:
print("cancel:", job_id, "\n") print("cancel:", job_id, "\n")
@ -404,7 +389,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
self.send_head() self.send_head()
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "reset": elif self.path == "/reset":
job_id = self.headers.get('job-id', "") job_id = self.headers.get('job-id', "")
job_frame = int(self.headers.get('job-frame', "-1")) job_frame = int(self.headers.get('job-frame', "-1"))
all = bool(self.headers.get('reset-all', "False")) all = bool(self.headers.get('reset-all', "False"))
@ -421,7 +406,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
else: # job not found else: # job not found
self.send_head(http.client.NO_CONTENT) self.send_head(http.client.NO_CONTENT)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "slave": elif self.path == "/slave":
length = int(self.headers['content-length']) length = int(self.headers['content-length'])
job_frame_string = self.headers['job-frame'] job_frame_string = self.headers['job-frame']
@ -431,7 +416,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
self.send_head(headers = {"slave-id": slave_id}) self.send_head(headers = {"slave-id": slave_id})
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "log": elif self.path == "/log":
slave_id = self.headers['slave-id'] slave_id = self.headers['slave-id']
slave = self.server.updateSlave(slave_id) slave = self.server.updateSlave(slave_id)
@ -460,7 +445,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
print(self.path) print(self.path)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
if self.path == "file": if self.path == "/file":
print("writing blend file") print("writing blend file")
self.server.stats("", "Receiving job") self.server.stats("", "Receiving job")
@ -504,7 +489,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
else: # job not found else: # job not found
self.send_head(http.client.NO_CONTENT) self.send_head(http.client.NO_CONTENT)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "render": elif self.path == "/render":
print("writing result file") print("writing result file")
self.server.stats("", "Receiving render result") self.server.stats("", "Receiving render result")
@ -547,7 +532,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
else: # invalid slave id else: # invalid slave id
self.send_head(http.client.NO_CONTENT) self.send_head(http.client.NO_CONTENT)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "log": elif self.path == "/log":
print("writing log file") print("writing log file")
self.server.stats("", "Receiving log file") self.server.stats("", "Receiving log file")
@ -587,6 +572,11 @@ class RenderMasterServer(http.server.HTTPServer):
self.job_id = 0 self.job_id = 0
self.path = path + "master_" + str(os.getpid()) + os.sep self.path = path + "master_" + str(os.getpid()) + os.sep
self.balancer = netrender.balancing.Balancer()
self.balancer.addRule(netrender.balancing.RatingCredit())
self.balancer.addException(netrender.balancing.ExcludeQueuedEmptyJob())
self.balancer.addPriority(netrender.balancing.NewJobPriority())
if not os.path.exists(self.path): if not os.path.exists(self.path):
os.mkdir(self.path) os.mkdir(self.path)
@ -616,7 +606,7 @@ class RenderMasterServer(http.server.HTTPServer):
self.jobs = [] self.jobs = []
def update(self): def update(self):
self.jobs.sort(key = groupKey) self.balancer.balance(self.jobs)
def removeJob(self, id): def removeJob(self, id):
job = self.jobs_map.pop(id) job = self.jobs_map.pop(id)
@ -644,8 +634,8 @@ class RenderMasterServer(http.server.HTTPServer):
def getNewJob(self, slave_id): def getNewJob(self, slave_id):
if self.jobs: if self.jobs:
for job in reversed(self.jobs): for job in self.jobs:
if job.status == JOB_QUEUED and job.framesLeft() > 0 and slave_id not in job.blacklist: if not self.balancer.applyExceptions(job) and slave_id not in job.blacklist:
return job, job.getFrames() return job, job.getFrames()
return None, None return None, None

@ -95,6 +95,18 @@ class RenderJob:
def __len__(self): def __len__(self):
return len(self.frames) return len(self.frames)
def countFrames(self, status=QUEUED):
total = 0
for j in self.frames:
if j.status == status:
total += 1
return total
def countSlaves(self):
return len(set((frame.slave for frame in self.frames if frame.status == DISPATCHED)))
def framesStatus(self): def framesStatus(self):
results = { results = {
QUEUED: 0, QUEUED: 0,

@ -89,7 +89,7 @@ class RENDER_OT_netclientstatus(bpy.types.Operator):
conn = clientConnection(context.scene) conn = clientConnection(context.scene)
if conn: if conn:
conn.request("GET", "status") conn.request("GET", "/status")
response = conn.getresponse() response = conn.getresponse()
print( response.status, response.reason ) print( response.status, response.reason )
@ -205,7 +205,7 @@ class RENDER_OT_netclientslaves(bpy.types.Operator):
conn = clientConnection(context.scene) conn = clientConnection(context.scene)
if conn: if conn:
conn.request("GET", "slave") conn.request("GET", "/slave")
response = conn.getresponse() response = conn.getresponse()
print( response.status, response.reason ) print( response.status, response.reason )
@ -258,7 +258,7 @@ class RENDER_OT_netclientcancel(bpy.types.Operator):
if conn: if conn:
job = bpy.data.netrender_jobs[netsettings.active_job_index] job = bpy.data.netrender_jobs[netsettings.active_job_index]
conn.request("POST", "cancel", headers={"job-id":job.id}) conn.request("POST", "/cancel", headers={"job-id":job.id})
response = conn.getresponse() response = conn.getresponse()
print( response.status, response.reason ) print( response.status, response.reason )

@ -33,7 +33,7 @@ def slave_Info():
return slave return slave
def testCancel(conn, job_id): def testCancel(conn, job_id):
conn.request("HEAD", "status", headers={"job-id":job_id}) conn.request("HEAD", "/status", headers={"job-id":job_id})
response = conn.getresponse() response = conn.getresponse()
# cancelled if job isn't found anymore # cancelled if job isn't found anymore
@ -47,7 +47,7 @@ def testFile(conn, job_id, slave_id, JOB_PREFIX, file_path, main_path = None):
if not os.path.exists(job_full_path): if not os.path.exists(job_full_path):
temp_path = JOB_PREFIX + "slave.temp.blend" temp_path = JOB_PREFIX + "slave.temp.blend"
conn.request("GET", "file", headers={"job-id": job_id, "slave-id":slave_id, "job-file":file_path}) conn.request("GET", "/file", headers={"job-id": job_id, "slave-id":slave_id, "job-file":file_path})
response = conn.getresponse() response = conn.getresponse()
if response.status != http.client.OK: if response.status != http.client.OK:
@ -76,7 +76,7 @@ def render_slave(engine, scene):
conn = clientConnection(scene) conn = clientConnection(scene)
if conn: if conn:
conn.request("POST", "slave", repr(slave_Info().serialize())) conn.request("POST", "/slave", repr(slave_Info().serialize()))
response = conn.getresponse() response = conn.getresponse()
slave_id = response.getheader("slave-id") slave_id = response.getheader("slave-id")
@ -87,7 +87,7 @@ def render_slave(engine, scene):
while not engine.test_break(): while not engine.test_break():
conn.request("GET", "job", headers={"slave-id":slave_id}) conn.request("GET", "/job", headers={"slave-id":slave_id})
response = conn.getresponse() response = conn.getresponse()
if response.status == http.client.OK: if response.status == http.client.OK:
@ -119,7 +119,7 @@ def render_slave(engine, scene):
# announce log to master # announce log to master
logfile = netrender.model.LogFile(job.id, [frame.number for frame in job.frames]) logfile = netrender.model.LogFile(job.id, [frame.number for frame in job.frames])
conn.request("POST", "log", bytes(repr(logfile.serialize()), encoding='utf8'), headers={"slave-id":slave_id}) conn.request("POST", "/log", bytes(repr(logfile.serialize()), encoding='utf8'), headers={"slave-id":slave_id})
response = conn.getresponse() response = conn.getresponse()
first_frame = job.frames[0].number first_frame = job.frames[0].number
@ -146,7 +146,7 @@ def render_slave(engine, scene):
if stdout: if stdout:
# (only need to update on one frame, they are linked # (only need to update on one frame, they are linked
headers["job-frame"] = str(first_frame) headers["job-frame"] = str(first_frame)
conn.request("PUT", "log", stdout, headers=headers) conn.request("PUT", "/log", stdout, headers=headers)
response = conn.getresponse() response = conn.getresponse()
stdout = bytes() stdout = bytes()
@ -173,7 +173,7 @@ def render_slave(engine, scene):
if stdout: if stdout:
# (only need to update on one frame, they are linked # (only need to update on one frame, they are linked
headers["job-frame"] = str(first_frame) headers["job-frame"] = str(first_frame)
conn.request("PUT", "log", stdout, headers=headers) conn.request("PUT", "/log", stdout, headers=headers)
response = conn.getresponse() response = conn.getresponse()
headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)} headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)}
@ -184,7 +184,7 @@ def render_slave(engine, scene):
headers["job-frame"] = str(frame.number) headers["job-frame"] = str(frame.number)
# send result back to server # send result back to server
f = open(JOB_PREFIX + "%06d" % frame.number + ".exr", 'rb') f = open(JOB_PREFIX + "%06d" % frame.number + ".exr", 'rb')
conn.request("PUT", "render", f, headers=headers) conn.request("PUT", "/render", f, headers=headers)
f.close() f.close()
response = conn.getresponse() response = conn.getresponse()
else: else:
@ -192,7 +192,7 @@ def render_slave(engine, scene):
for frame in job.frames: for frame in job.frames:
headers["job-frame"] = str(frame.number) headers["job-frame"] = str(frame.number)
# send error result back to server # send error result back to server
conn.request("PUT", "render", headers=headers) conn.request("PUT", "/render", headers=headers)
response = conn.getresponse() response = conn.getresponse()
else: else:
if timeout < MAX_TIMEOUT: if timeout < MAX_TIMEOUT:

@ -8,6 +8,12 @@ import netrender.model
VERSION = b"0.5" VERSION = b"0.5"
# Jobs status
JOB_WAITING = 0 # before all data has been entered
JOB_PAUSED = 1 # paused by user
JOB_QUEUED = 2 # ready to be dispatched
# Frames status
QUEUED = 0 QUEUED = 0
DISPATCHED = 1 DISPATCHED = 1
DONE = 2 DONE = 2
@ -36,7 +42,7 @@ def clientConnection(scene):
return None return None
def clientVerifyVersion(conn): def clientVerifyVersion(conn):
conn.request("GET", "version") conn.request("GET", "/version")
response = conn.getresponse() response = conn.getresponse()
if response.status != http.client.OK: if response.status != http.client.OK: