Skip to content

Commit

Permalink
Update to latest p4a commit.
Browse files Browse the repository at this point in the history
Use Java to launch tasks for avoid introspection issues.
  • Loading branch information
rtibbles committed Feb 25, 2023
1 parent 8a8b962 commit 8d00eca
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 63 deletions.
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
cython
virtualenv
git+https://github.com/learningequality/python-for-android@5dc7bdb3364f5ed5b573ceffdb364382ae181955#egg=python-for-android
git+https://github.com/learningequality/python-for-android@6ba12f935ff753a58d396190c24a7a387b95ef9c#egg=python-for-android
59 changes: 59 additions & 0 deletions src/java/org/learningequality/Task.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.learningequality;

import androidx.work.Data;
import androidx.work.WorkManager;
import androidx.work.WorkRequest;
import androidx.work.OneTimeWorkRequest;
import androidx.work.PeriodicWorkRequest;
import androidx.work.BackoffPolicy;
import androidx.work.ExistingWorkPolicy;
import androidx.work.ExistingPeriodicWorkPolicy;
import java.util.concurrent.TimeUnit;

import org.learningequality.Kolibri.TaskworkerWorker;
import org.kivy.android.PythonActivity;


public class Task {
public static void enqueueIndefinitely(String id, int interval, int delay, int retryInterval) {
WorkManager workManager = WorkManager.getInstance(PythonActivity.mActivity);
Data data = TaskworkerWorker.buildInputData(id);

PeriodicWorkRequest.Builder workRequestBuilder = new PeriodicWorkRequest.Builder(
TaskworkerWorker.class, interval, TimeUnit.SECONDS
);

if (retryInterval > 0) {
workRequestBuilder.setBackoffCriteria(
BackoffPolicy.LINEAR, retryInterval, TimeUnit.SECONDS
);
}
if (delay > 0) {
workRequestBuilder.setInitialDelay(delay, TimeUnit.SECONDS);
}
workRequestBuilder.setInputData(data);
PeriodicWorkRequest workRequest = workRequestBuilder.build();
workManager.enqueueUniquePeriodicWork(id, ExistingPeriodicWorkPolicy.KEEP, workRequest);
}
public static void enqueueOnce(String id, int delay, int retryInterval, boolean keep) {
WorkManager workManager = WorkManager.getInstance(PythonActivity.mActivity);
Data data = TaskworkerWorker.buildInputData(id);

OneTimeWorkRequest.Builder workRequestBuilder = new OneTimeWorkRequest.Builder(TaskworkerWorker.class);
if (retryInterval > 0) {
workRequestBuilder.setBackoffCriteria(
BackoffPolicy.LINEAR, retryInterval, TimeUnit.SECONDS
);
}
if (delay > 0) {
workRequestBuilder.setInitialDelay(delay, TimeUnit.SECONDS);
}
workRequestBuilder.setInputData(data);
OneTimeWorkRequest workRequest = workRequestBuilder.build();
if (keep) {
workManager.enqueueUniqueWork(id, ExistingWorkPolicy.KEEP, workRequest);
} else {
workManager.enqueueUniqueWork(id, ExistingWorkPolicy.APPEND_OR_REPLACE, workRequest);
}
}
}
72 changes: 12 additions & 60 deletions src/kolibri_tasks.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,9 @@
from datetime import datetime
from datetime import timedelta

from android_utils import PythonActivity
from jnius import autoclass


WorkManager = autoclass("androidx.work.WorkManager")
OneTimeWorkRequestBuilder = autoclass("androidx.work.OneTimeWorkRequest$Builder")
PeriodicWorkRequestBuilder = autoclass("androidx.work.PeriodicWorkRequest$Builder")
BackoffPolicy = autoclass("androidx.work.BackoffPolicy")
ExistingWorkPolicy = autoclass("androidx.work.ExistingWorkPolicy")
ExistingPeriodicWorkPolicy = autoclass("androidx.work.ExistingPeriodicWorkPolicy")
TimeUnit = autoclass("java.util.concurrent$TimeUnit")

TaskWorker = autoclass("org.learningequality.Kolibri.TaskWorker")


def get_work_manager():
return WorkManager.getInstance(PythonActivity.mActivity)
Task = autoclass("org.learningequality.Task")


def queue_task(
Expand All @@ -31,35 +17,23 @@ def queue_task(
):
if id:
id = str(id)
data = TaskWorker.buildInputData(id)
delay = (
max(0, (scheduled_time - datetime.now()).total_seconds())
if scheduled_time
else 0
)
retry_interval = retry_interval if retry_interval else 0

if repeat is None:
# Kolibri uses `None` for repeat to indicate a task that repeats indefinitely
# in this case it is suitable for the Android PeriodicWorkRequest as that is
# designed for indefinitely repeating tasks.
work_request = PeriodicWorkRequestBuilder(
TaskWorker._class, interval, TimeUnit.SECONDS
)
existing_work_policy = ExistingPeriodicWorkPolicy.KEEP
enqueue_method = get_work_manager().enqueueUniquePeriodicWork
Task.enqueueIndefinitely(id, interval, delay, retry_interval)
else:
work_request = OneTimeWorkRequestBuilder(TaskWorker._class)
existing_work_policy = (
ExistingWorkPolicy.KEEP
if keep
else ExistingWorkPolicy.APPEND_OR_REPLACE
)
enqueue_method = get_work_manager().enqueueUniqueWork
if retry_interval is not None:
work_request.setBackOffCriteria(
BackoffPolicy.LINEAR, retry_interval, TimeUnit.SECONDS
)
if scheduled_time:
delay = max(0, (scheduled_time - datetime.now()).total_seconds())
if delay:
work_request.setInitialDelay(delay, TimeUnit.SECONDS)
work_request.setInputData(data).build()
enqueue_method(id, existing_work_policy, work_request)
# Android has no mechanism for scheduling a limited run of repeating tasks
# so anything else is just scheduled once, and we use the task_updates function
# below to reschedule the next invocation.
Task.enqueueOnce(id, delay, retry_interval, keep)


def task_updates(job, orm_job, state=None, **kwargs):
Expand All @@ -80,28 +54,6 @@ def task_updates(job, orm_job, state=None, **kwargs):
)


def execute_job(job_id):
from django.db import connection as django_connection

from kolibri.core.tasks.storage import Storage
from kolibri.core.tasks.utils import db_connection

connection = db_connection()

storage = Storage(
connection, schedule_hooks=[queue_task], update_hooks=[task_updates]
)

job = storage.get_job(job_id)

job.execute()

connection.dispose()

# Close any django connections opened here
django_connection.close()


def start_default_tasks():
from kolibri.core.analytics.tasks import schedule_ping
from kolibri.core.deviceadmin.tasks import schedule_vacuum
Expand Down
6 changes: 4 additions & 2 deletions src/taskworker.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@

import initialization # noqa: F401 keep this first, to ensure we're set up for other imports
from kolibri.main import initialize
from kolibri_tasks import execute_job

logging.info("Starting Kolibri task worker")

initialize(skip_update=True)

job_id = environ.get("PYTHON_SERVICE_ARGUMENT", "")
job_id = environ.get("PYTHON_WORKER_ARGUMENT", "")

# Import this after we have initialized Kolibri
from kolibri.core.tasks.worker import execute_job # noqa: E402

execute_job(job_id)

0 comments on commit 8d00eca

Please sign in to comment.