mirror of
https://github.com/spl0k/supysonic.git
synced 2024-12-22 17:06:17 +00:00
Fix issues with hanging transcoding processes
When a connection that is consuming a generated response is closed, Flask closes the generator making it raise the special `GeneratorExit` exception when the program tries to yield from it again. Because the `transcode` function was called (returning a generator) before being passed into `set_generated`, the exception was being handled in the wrong order. By passing the `transcode` function to `set_generated` and letting `set_transcode` call it to return a generator while generating the response for the client, the exception properly bubbles up through `transcode` into `set_generated`. This allows both of them to handle it properly by stopping the subproceses and not caching the incomplete response data respectively.
This commit is contained in:
parent
f106923f17
commit
0ac2376e07
@ -127,7 +127,7 @@ def stream_media():
|
|||||||
if dec_proc != None:
|
if dec_proc != None:
|
||||||
dec_proc.wait()
|
dec_proc.wait()
|
||||||
proc.wait()
|
proc.wait()
|
||||||
resp_content = cache.set_generated(cache_key, transcode())
|
resp_content = cache.set_generated(cache_key, transcode)
|
||||||
|
|
||||||
logger.info('Transcoding track {0.id} for user {1.id}. Source: {2} at {0.bitrate}kbps. Dest: {3} at {4}kbps'.format(res, request.user, src_suffix, dst_suffix, dst_bitrate))
|
logger.info('Transcoding track {0.id} for user {1.id}. Source: {2} at {0.bitrate}kbps. Dest: {3} at {4}kbps'.format(res, request.user, src_suffix, dst_suffix, dst_bitrate))
|
||||||
response = Response(resp_content, mimetype=dst_mimetype)
|
response = Response(resp_content, mimetype=dst_mimetype)
|
||||||
|
@ -161,17 +161,19 @@ class Cache(object):
|
|||||||
f.write(value)
|
f.write(value)
|
||||||
return self._filepath(key)
|
return self._filepath(key)
|
||||||
|
|
||||||
def set_generated(self, key, gen):
|
def set_generated(self, key, gen_function):
|
||||||
"""Pass the generated values through and set the end result in the cache
|
"""Pass the values yielded from the generator function through and set
|
||||||
|
the end result in the cache.
|
||||||
|
|
||||||
The contents will be set into the cache when the generator completes.
|
The contents will be set into the cache only if and when the generator
|
||||||
|
completes.
|
||||||
|
|
||||||
Ex:
|
Ex:
|
||||||
>>> for x in cache.set_generated(key, some_generator()):
|
>>> for x in cache.set_generated(key, generator_function):
|
||||||
... print(x)
|
... print(x)
|
||||||
"""
|
"""
|
||||||
with self.set_fileobj(key) as f:
|
with self.set_fileobj(key) as f:
|
||||||
for data in gen:
|
for data in gen_function():
|
||||||
f.write(data)
|
f.write(data)
|
||||||
yield data
|
yield data
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ class CacheTestCase(unittest.TestCase):
|
|||||||
yield b
|
yield b
|
||||||
|
|
||||||
t = []
|
t = []
|
||||||
for x in cache.set_generated("key", gen()):
|
for x in cache.set_generated("key", gen):
|
||||||
t.append(x)
|
t.append(x)
|
||||||
self.assertEqual(cache.size, 0)
|
self.assertEqual(cache.size, 0)
|
||||||
self.assertFalse(cache.has("key"))
|
self.assertFalse(cache.has("key"))
|
||||||
@ -103,7 +103,7 @@ class CacheTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(cache.get_value("key"), val)
|
self.assertEqual(cache.get_value("key"), val)
|
||||||
|
|
||||||
with cache.get_fileobj("key") as f:
|
with cache.get_fileobj("key") as f:
|
||||||
self.assertEquals(f.read(), val)
|
self.assertEqual(f.read(), val)
|
||||||
|
|
||||||
with open(cache.get("key"), 'rb') as f:
|
with open(cache.get("key"), 'rb') as f:
|
||||||
self.assertEqual(f.read(), val)
|
self.assertEqual(f.read(), val)
|
||||||
@ -162,7 +162,7 @@ class CacheTestCase(unittest.TestCase):
|
|||||||
yield b
|
yield b
|
||||||
|
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
for x in cache.set_generated("key", gen()):
|
for x in cache.set_generated("key", gen):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Make sure no partial files are left after the error
|
# Make sure no partial files are left after the error
|
||||||
@ -174,8 +174,8 @@ class CacheTestCase(unittest.TestCase):
|
|||||||
for b in [b'0', b'12', b'345', b'6789']:
|
for b in [b'0', b'12', b'345', b'6789']:
|
||||||
yield b
|
yield b
|
||||||
|
|
||||||
g1 = cache.set_generated("key", gen())
|
g1 = cache.set_generated("key", gen)
|
||||||
g2 = cache.set_generated("key", gen())
|
g2 = cache.set_generated("key", gen)
|
||||||
|
|
||||||
next(g1)
|
next(g1)
|
||||||
files = os.listdir(self.__dir)
|
files = os.listdir(self.__dir)
|
||||||
|
Loading…
Reference in New Issue
Block a user