במהלך בדיקת אפליקציה ב-Apple, הבנייה עלולה להידחות אם חסרה תכונת ייצוא נתונים. סעיף 20 ל-GDPR מחייב לספק למשתמשים עותק של הנתונים שלהם בפורמט קריא למכונה ונייד. ללא זה, האפליקציה שלך מסתכנת בדחייה מ-App Store או Google Play. במשך 9 שנים, יישמנו תכונה זו ביותר מ-50 פרויקטים עם עומסים של עד 100,000 משתמשים. בעיה אופיינית: מפתחים מנסים לאסוף נתונים באופן סינכרוני בתגובה לבקשת HTTP, מה שמוביל לזמן קצוב שחורג כאשר הנפח עולה על 1,000 רשומות. במקום זאת, אנו משתמשים בתבנית אסינכרונית עם תור משימות וקישור הורדה זמני.
אילו נתונים לייצא ולפי אילו כללים?
הסט המינימלי לפי GDPR: כל הנתונים שהמשתמש סיפק ישירות (פרופיל, הגדרות, תוכן) ונתונים שנוצרו כתוצאה משימוש בשירות (היסטוריית פעולות, עסקאות, העדפות). בדרך כלל, הנפח נע בין 500 ל-10,000 רשומות למשתמש.
| סוג נתונים | כלול | דוגמה |
|---|---|---|
| פרופיל משתמש | כן | שם, אימייל, תמונת פרופיל |
| הגדרות | כן | שפה, ערכת נושא, התראות |
| תוכן משתמש | כן | הודעות, הזמנות, תגובות |
| היסטוריית פעולות | כן | התחברויות, רכישות, צפיות |
| צבירים אנליטיים | לא | DAU, שימור, משקלי ML |
| יומני טכניים של שרת | לא | IP, user-agent, יומני גישה |
| נתונים של משתמשים אחרים | לא | פרופילים, הודעות של אחרים |
פורמטים: JSON מועדף לקריאות מכונה, CSV למשתמשים שרוצים לפתוח ב-Excel. ארכיון ZIP עם מספר קבצים הוא נוהג סטנדרטי, כמו ב-Google Takeout. אנו מתמחים בפיתוח מובייל תואם GDPR, ולכן אנו שוקלים את כל דרישות ניידות הנתונים.
ייצוא סינכרוני לעומת אסינכרוני: מה לבחור?
ייצוא סינכרוני פשוט יותר ליישום, אך עבור נפחים העולים על 5,000 רשומות, הוא חוסם את החיבור וגורם לזמן קצוב שחורג. ייצוא אסינכרוני אמין פי 10 בעומסים גבוהים: הוא מתקנה ל-10 בקשות לדקה ללא אובדן ביצועים. זמן תגובת ה-API יורד מ-10–15 שניות ל-200 אלפיות השנייה, בעוד שהייצוא המלא אורך 2–3 דקות—המשתמש מקבל הודעה כשזה מוכן. חיסכון בתשתית: ייצוא אסינכרוני מפחית עומסי שיא, ומוריד עלויות שרת בעד 30%.
| תכונה | סינכרוני | אסינכרוני |
|---|---|---|
| זמן תגובת API | 5-15 שניות | <200 אלפיות השנייה |
| אמינות עבור >5000 רשומות | זמן קצוב שחורג | יציב |
| עומס מסד נתונים | גבוה (שיא) | חלק (תור) |
| חוויית משתמש | המתנה | סקר + push |
כיצד ליישם ייצוא בצד השרת ללא חסימה?
ייצוא הוא פעולה כבדה פוטנציאלית. תגובת HTTP סינכרונית עבור 10,000 רשומות אורכת 5–10 שניות, החורגת מזמן הקצוב הסטנדרטי של 30 שניות. הפתרון הנכון הוא תבנית אסינכרונית עם סקר או webhook.
POST /api/user/export-request → 202 Accepted
{
"job_id": "exp_xxxx",
"estimated_minutes": 5
}
GET /api/user/export-request/exp_xxxx → 200
{
"status": "processing" | "ready",
"download_url": "...",
"expires_at": "..."
}משימת רקע (Celery או Laravel Queue) אוספת נתונים מכל הטבלאות, יוצרת ארכיון, מעלה אותו ל-S3 עם URL חתום מראש בתוקף ל-24–72 שעות. לאחר השלמה—הודעת push או אימייל. URL חתום מראש עם TTL הוא קריטי: לעולם אל תחשוף קישורי S3 ישירים ללא הרשאה כדי למנוע דליפות נתונים. בפרויקט אחד עם 50,000 משתמשים, התור האסינכרוני הפחית את עומס מסד הנתונים פי 20 בהשוואה לגישה הסינכרונית.
דוגמה לתצורת תור Celery
לעיבוד רקע אנו משתמשים ב-Celery עם Redis כברוקר. משימת הייצוא נראית כך:@app.task(bind=True, max_retries=3, default_retry_delay=300)
def export_user_data(self, user_id, job_id):
try:
user_data = collect_user_data(user_id)
archive = create_zip_archive(user_data)
presigned_url = upload_to_s3(archive, expires_in=86400)
update_job_status(job_id, 'ready', presigned_url)
send_push_notification(user_id, 'Экспорт готов')
except Exception as e:
self.retry(exc=e) זרימת לקוח: SwiftUI ו-Jetpack Compose
// iOS — запрос экспорта и polling статуса
class DataExportViewModel: ObservableObject {
@Published var exportState: ExportState = .idle
func requestExport() async {
exportState = .requesting
let job = try await api.requestDataExport()
exportState = .processing(jobID: job.id)
await pollStatus(jobID: job.id)
}
private func pollStatus(jobID: String) async {
while true {
try? await Task.sleep(nanoseconds: 30_000_000_000) // 30 секунд
let status = try await api.getExportStatus(jobID: jobID)
if status.isReady {
exportState = .ready(downloadURL: status.downloadURL!)
return
}
}
}
}לאחר קבלת POST /api/user/export-request → 202 Accepted { "job_id": "exp_xxxx", "estimated_minutes": 5 } GET /api/user/export-request/exp_xxxx → 200 { "status": "processing" | "ready", "download_url": "...", "expires_at": "..." } , בקש מהמשתמש לשמור את הקובץ דרך @app.task(bind=True, max_retries=3, default_retry_delay=300) def export_user_data(self, user_id, job_id): try: user_data = collect_user_data(user_id) archive = create_zip_archive(user_data) presigned_url = upload_to_s3(archive, expires_in=86400) update_job_status(job_id, 'ready', presigned_url) send_push_notification(user_id, 'Экспорт готов') except Exception as e: self.retry(exc=e) (iOS) או // iOS — запрос экспорта и polling статуса class DataExportViewModel: ObservableObject { @Published var exportState: ExportState = .idle func requestExport() async { exportState = .requesting let job = try await api.requestDataExport() exportState = .processing(jobID: job.id) await pollStatus(jobID: job.id) } private func pollStatus(jobID: String) async { while true { try? await Task.sleep(nanoseconds: 30_000_000_000) // 30 секунд let status = try await api.getExportStatus(jobID: jobID) if status.isReady { exportState = .ready(downloadURL: status.downloadURL!) return } } } } (Android). אל תשמור ל-ready אוטומטית ללא הסכמה.
באיזו תדירות משתמש יכול לבקש ייצוא?
הגבל את התדירות לבקשה אחת כל 24–48 שעות. ללא מגבלות, משתמשים עלולים ליצור עשרות בקשות ביום, ולהעמיס על מסד הנתונים. הצג את תאריך הייצוא האחרון ואת הזמן עד לבקשה האפשרית הבאה.
מדוע הגישה האסינכרונית היא הפתרון האמין היחיד?
ייצוא סינכרוני פשוט ליישום, אך עבור נפחים מעל 5,000 רשומות הוא חוסם את החיבור וגורם לזמן קצוב שחורג. אסינכרוני, לעומת זאת, מתקנה: אנו מעבדים עד 10 בקשות לדקה ללא אובדן ביצועים. ייצוא מלא למשתמש אחד אורך מ-10–15 שניות (סינכרוני) עד 2–3 דקות (אסינכרוני), אך ה-API מגיב ב-200 אלפיות השנייה. עבור המשתמש, זה אומר אפליקציה יציבה יותר והודעה כשהקובץ מוכן.
מה העבודה שלנו כוללת
- ביקורת על הארכיטקטורה והנתונים הנוכחיים
- עיצוב תוכנית הייצוא (API, תורים, אחסון)
- יישום API בצד השרת ומשימות רקע
- ממשק לקוח עם סקר והצגת התקדמות
- בדיקות עם נתונים אמיתיים (ReplayKit, TestFlight)
- תיעוד ותמיכה לאחר השקה
צור קשר כדי להעריך את הפרויקט שלך—נאמוד עלות ולוח זמנים ללא התחייבות. הזמן ביקורת על הארכיטקטורה הנוכחית שלך—נכין את הפתרון האופטימלי לסט הטכנולוגי שלך.







