Skip to content

Commit 610e88a

Browse files
authored
feat(service): support chunked file uploads (#2892)
1 parent 73866f2 commit 610e88a

25 files changed

+719
-33
lines changed

helm-chart/renku-core/templates/configmap.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ data:
77
{{- range $version := .Values.versions }}
88
upstream {{ $version.name }} {
99
server {{ include "renku-core.fullname" $ }}-{{ $version.name }};
10+
keepalive 32;
11+
keepalive_timeout 60s;
1012
}
1113
{{ end }}
1214
@@ -30,12 +32,20 @@ data:
3032
rewrite /renku/{{ $version.prefix }}/(.*) /renku/$1 break;
3133
proxy_set_header Host $host;
3234
proxy_pass http://{{ $version.name }};
35+
proxy_send_timeout {{ $.Values.requestTimeout }}s;
36+
proxy_read_timeout {{ $.Values.requestTimeout }}s;
37+
proxy_http_version 1.1;
38+
proxy_set_header "Connection" "";
3339
}
3440
{{- end }}
3541
3642
location /renku {
3743
proxy_set_header Host $host;
3844
proxy_pass http://{{ .Values.versions.latest.name }};
45+
proxy_send_timeout {{ $.Values.requestTimeout }}s;
46+
proxy_read_timeout {{ $.Values.requestTimeout }}s;
47+
proxy_http_version 1.1;
48+
proxy_set_header "Connection" "";
3949
}
4050
}
4151
version.json: |

helm-chart/renku-core/templates/deployment.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ spec:
104104
value: {{ $.Values.projectCloneDepth | quote }}
105105
- name: TEMPLATE_CLONE_DEPTH_DEFAULT
106106
value: {{ $.Values.templateCloneDepth | quote }}
107+
- name: MAX_CONTENT_LENGTH
108+
value: {{ $.Values.maximumUploadSizeBytes | quote }}
109+
- name: REQUEST_TIMEOUT
110+
value: {{ $.Values.requestTimeout | quote }}
107111
- name: CORE_SERVICE_PREFIX
108112
value: /renku
109113
- name: CORE_SERVICE_API_BASE_PATH

helm-chart/renku-core/values.schema.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@
2626
"type": "integer",
2727
"minimum": 1
2828
},
29+
"maximumUploadSizeBytes": {
30+
"description": "Maximum allowed file upload size.",
31+
"type": "string",
32+
"minimum": 1,
33+
"pattern": "^\\d+"
34+
},
35+
"requestTimeout": {
36+
"description": "Time before requests time out.",
37+
"type": "integer"
38+
},
2939
"datasetsWorkerQueues": {
3040
"description": "Name of the worker queue for dataset jobs",
3141
"type": "string"

helm-chart/renku-core/values.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ cacheDirectory: /svc/cache
3939
cleanupInterval: 60 # NOTE: This needs to be a divisor of, and less than cleanupFilesTTL|cleanupProjectsTTL.
4040
projectCloneDepth: 1
4141
templateCloneDepth: 1
42+
maximumUploadSizeBytes: "1073741824" # 1 Gigabyte, store as string to keep Helm from converting it to scientific notation
43+
requestTimeout: 600
4244

4345
datasetsWorkerQueues: datasets.jobs,delayed.ctrl.DatasetsCreateCtrl,delayed.ctrl.DatasetsAddFileCtrl,delayed.ctrl.DatasetsRemoveCtrl,delayed.ctrl.DatasetsImportCtrl,delayed.ctrl.DatasetsEditCtrl,delayed.ctrl.DatasetsUnlinkCtrl
4446
managementWorkerQueues: cache.cleanup.files,cache.cleanup.projects,delayed.ctrl.MigrateProjectCtrl,delayed.ctrl.SetConfigCtrl

poetry.lock

Lines changed: 81 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ deepdiff = "^5.8.0"
7070
deepmerge = "==1.0.1"
7171
docker = "<6,>=3.7.2"
7272
environ-config = ">=18.2.0,<22.2.0"
73-
fakeredis = { version = ">=1.4.1,<1.7.2", optional = true }
73+
fakeredis = { version = ">=1.4.1,<1.7.2", extras = ["lua"], optional = true }
7474
filelock = ">=3.3.0,<3.6.1"
7575
flake8 = { version = "<4.0,>=3.8", optional = true } #wait for https://github.com/flakehell/flakehell/pull/23 to be merged before bumping
7676
flakehell = { version = ">=0.9.0,<1.0.*", optional = true }

renku/ui/cli/service.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ def run_api(addr="0.0.0.0", port=8080, timeout=600):
4444
svc_num_workers = os.getenv("RENKU_SVC_NUM_WORKERS", "1")
4545
svc_num_threads = os.getenv("RENKU_SVC_NUM_THREADS", "2")
4646

47+
svc_timeout = int(os.getenv("REQUEST_TIMEOUT", timeout))
48+
4749
loading_opt = "--preload"
4850

4951
sys.argv = [
@@ -53,7 +55,7 @@ def run_api(addr="0.0.0.0", port=8080, timeout=600):
5355
"-b",
5456
f"{addr}:{port}",
5557
"--timeout",
56-
f"{timeout}",
58+
f"{svc_timeout}",
5759
"--workers",
5860
svc_num_workers,
5961
"--worker-class",

renku/ui/service/cache/files.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@
1717
# limitations under the License.
1818
"""Renku service files cache management."""
1919
from renku.ui.service.cache.base import BaseCache
20-
from renku.ui.service.cache.models.file import File
20+
from renku.ui.service.cache.models.file import File, FileChunk
2121
from renku.ui.service.cache.models.user import User
22-
from renku.ui.service.cache.serializers.file import FileSchema
22+
from renku.ui.service.cache.serializers.file import FileChunkSchema, FileSchema
2323

2424

2525
class FileManagementCache(BaseCache):
2626
"""File management cache."""
2727

2828
file_schema = FileSchema()
29+
chunk_schema = FileChunkSchema()
2930

3031
def set_file(self, user, file_data):
3132
"""Cache file metadata."""
@@ -40,6 +41,15 @@ def set_files(self, user, files):
4041
"""Cache files metadata."""
4142
return [self.set_file(user, file_) for file_ in files]
4243

44+
def set_file_chunk(self, user, chunk_data):
45+
"""Cache chunk metadata."""
46+
chunk_data.update({"user_id": user.user_id})
47+
48+
chunk_obj = self.chunk_schema.load(chunk_data)
49+
chunk_obj.save()
50+
51+
return chunk_obj
52+
4353
@staticmethod
4454
def get_file(user, file_id):
4555
"""Get user file."""
@@ -55,6 +65,21 @@ def get_files(user):
5565
"""Get all user cached files."""
5666
return File.query(File.user_id == user.user_id)
5767

68+
@staticmethod
69+
def get_chunks(user, chunked_id=None):
70+
"""Get all user chunks for a file."""
71+
if chunked_id is not None:
72+
return FileChunk.query(FileChunk.user_id == user.user_id and FileChunk.chunked_id == chunked_id)
73+
return FileChunk.query(FileChunk.user_id == user.user_id)
74+
75+
@staticmethod
76+
def invalidate_chunks(user, chunked_id):
77+
"""Remove all user chunks for a file."""
78+
chunks = FileChunk.query(FileChunk.user_id == user.user_id and FileChunk.chunked_id == chunked_id)
79+
80+
for chunk in chunks:
81+
chunk.delete()
82+
5883
@staticmethod
5984
def invalidate_file(user, file_id):
6085
"""Remove users file records."""
@@ -69,3 +94,8 @@ def user_files(self):
6994
"""Iterate through all cached files."""
7095
for user in User.all():
7196
yield user, self.get_files(user)
97+
98+
def user_chunks(self):
99+
"""Iterate through all cached files."""
100+
for user in User.all():
101+
yield user, self.get_chunks(user)

0 commit comments

Comments
 (0)