diff --git a/ippisite/ippidb/admin.py b/ippisite/ippidb/admin.py
index 9ba83536aeb284fd46068907c0f1353c3c562ce1..e0c6126ad817dcc364d4e98747c238da0cd795e6 100644
--- a/ippisite/ippidb/admin.py
+++ b/ippisite/ippidb/admin.py
@@ -29,7 +29,7 @@ from .models import (
     Contribution,
     Job,
 )
-from .tasks import launch_validate_contributions
+from .tasks import launch_validate_contributions, launch_plots_computing
 
 
 class ViewOnSiteModelAdmin(admin.ModelAdmin):
@@ -191,7 +191,7 @@ class ContributionModelAdmin(ViewOnSiteModelAdmin):
 
     def validate_contributions(self, request, queryset):
         ids = [id for id in queryset.values_list("id", flat=True)]
-        launch_validate_contributions.delay(ids)
+        launch_validate_contributions(ids)
         self.message_user(
             request,
             f"validation started for contributions(s) "
diff --git a/ippisite/ippidb/tasks.py b/ippisite/ippidb/tasks.py
index 79337a627e2c171b82cff097c813b4e5f7b06163..5231eb4f8de6a54cfbb145c9a6b2b9790da83954 100644
--- a/ippisite/ippidb/tasks.py
+++ b/ippisite/ippidb/tasks.py
@@ -8,7 +8,7 @@ import time
 import random
 
 
-from celery import shared_task, task, states
+from celery import task, states, chain, group
 from ippisite.decorator import MonitorTask
 import matplotlib.pyplot as plt
 
@@ -23,7 +23,9 @@ from django.forms.models import model_to_dict
 
 from .models import (
     Compound,
+    CompoundJob,
     Contribution,
+    Job,
     update_compound_cached_properties,
     LeLleBiplotData,
     PcaBiplotData,
@@ -273,6 +275,7 @@ def generate_pca_plot():
         principal_df = principal_df.iloc[:, 0:2]
         principal_df = principal_df.rename(columns={0: "x", 1: "y"})
         final_df = pd.concat([principal_df, df[["family", "id"]]], axis=1)
+        final_df.dropna(how="any", inplace=True)
         for index, row in final_df.iterrows():
             smiles = Compound.objects.get(id=row.id).canonical_smile
             pca_data.append(
@@ -318,72 +321,88 @@ def launch_test_command_caching(self):
 
 
 @task(base=MonitorTask, bind=True)
-def launch_validate_contributions(self, contribution_ids):
-    """
-    This task will perform, for a given set of contributions,
-    all computations on the compounds and validate the contributions
-    It also regenerates the LE-LLE and PCA plots
-    """
+def run_compute_compound_properties(self, compound_id):
     self.update_state(state=states.STARTED)
-    for cont in Contribution.objects.filter(id__in=contribution_ids):
-        for compound_action in cont.ppi.compoundaction_set.all():
-            compound = compound_action.compound
-            self.write(std_out=f"Starting computation of compound properties for {compound.id}")
-            compute_compound_properties([compound.id])
-            self.write(std_out=f"Finished computation of compound properties for {compound.id}")
-            self.write(std_out=f"Starting caching of compound properties for {compound.id}")
-            update_compound_cached_properties(
-                Compound.objects.filter(id__in=[compound.id])
-            )
-            self.write(std_out=f"Finished caching of compound properties for {compound.id}")
-            self.write(std_out=f"Starting computing Drugbank similarity for {compound.id}")
-            compute_drugbank_similarity([compound.id])
-            self.write(std_out=f"Finished computing Drugbank similarity for {compound.id}")
-            self.write(std_out=f"Starting validation of compounds {compound.id}")
-            validate([compound.id])
-            self.write(std_out=f"Finished validation of compounds {compound.id}")
-    self.write(std_out=f"Starting computing LE-LLE plot")
-    generate_le_lle_plot()
-    self.write(std_out=f"Finished computing LE-LLE plot")
-    self.write(std_out=f"Starting computing PCA plot")
-    generate_pca_plot()
-    self.write(std_out=f"Finished computing PCA plot")
+    cj = CompoundJob()
+    cj.compound = Compound.objects.get(id=compound_id)
+    cj.job = Job.objects.get(task_result__task_id=self.task_id)
+    cj.save()
+    self.write(std_out=f"Starting computation of compound properties for {compound_id}")
+    compute_compound_properties([compound_id])
+    self.write(std_out=f"Finished computation of compound properties for {compound_id}")
+
 
 @task(base=MonitorTask, bind=True)
-def launch_compound_properties_caching(self):
-    """
-    This task will perform, for all already validated compounds,
-    the caching of the properties.
-    """
+def run_update_compound_cached_properties(self, compound_ids):
     self.update_state(state=states.STARTED)
-    validated_compounds = Compound.objects.validated()
-    self.write(std_out=f"Starting caching of compound properties for all compounds")
-    update_compound_cached_properties(validated_compounds)
-    self.write(std_out=f"Finished caching of compound properties for all compounds")
+    self.write(std_out=f"Starting caching of compound properties for {compound_ids}")
+    update_compound_cached_properties(Compound.objects.filter(id__in=compound_ids))
+    self.write(std_out=f"Finished caching of compound properties for {compound_ids}")
 
 
 @task(base=MonitorTask, bind=True)
-def launch_drugbank_similarity_computing(self):
-    """
-    This task will perform, for all already validated compounds,
-    the computing of drugbank similarity.
-    """
+def run_compute_drugbank_similarity(self, compound_ids):
     self.update_state(state=states.STARTED)
-    validated_compounds = Compound.objects.validated()
-    self.write(std_out=f"Starting computing Drugbank similarity for all compounds")
-    compute_drugbank_similarity(validated_compounds)
-    self.write(std_out=f"Finished computing Drugbank similarity for all compounds")
+    self.write(std_out=f"Starting computing Drugbank similarity for {compound_ids}")
+    compute_drugbank_similarity(compound_ids)
+    self.write(std_out=f"Finished computing Drugbank similarity for {compound_ids}")
 
 
 @task(base=MonitorTask, bind=True)
-def launch_plots_computing(self):
-    """
-    This task will perform the computing of LE-LLE and PCA plots.
-    """
+def run_validate(self, compound_ids):
+    self.update_state(state=states.STARTED)
+    self.write(std_out=f"Starting validation of compounds {compound_ids}")
+    validate(compound_ids)
+    self.write(std_out=f"Finished validation of compounds {compound_ids}")
+
+
+@task(base=MonitorTask, bind=True)
+def run_le_lle_plot(self):
     self.update_state(state=states.STARTED)
     self.write(std_out=f"Starting computing LE-LLE plot")
     generate_le_lle_plot()
     self.write(std_out=f"Finished computing LE-LLE plot")
+
+
+@task(base=MonitorTask, bind=True)
+def run_pca_plot(self):
+    self.update_state(state=states.STARTED)
     self.write(std_out=f"Starting computing PCA plot")
     generate_pca_plot()
     self.write(std_out=f"Finished computing PCA plot")
+
+
+def launch_validate_contributions(contribution_ids):
+    contribution_jobs = []
+    for cont in Contribution.objects.filter(id__in=contribution_ids):
+        compound_ids = [
+            compound_action.compound.id
+            for compound_action in cont.ppi.compoundaction_set.all()
+        ]
+        # build a group of jobs, one job for each compound properties computation
+        run_compounds_properties_computation_group = group(
+            [
+                run_compute_compound_properties.si(compound_id)
+                for compound_id in compound_ids
+            ]
+        )
+        # build the "main" job
+        compounds_properties_computation_group = chain(
+            run_compounds_properties_computation_group,
+            run_update_compound_cached_properties.si(compound_ids),
+            run_compute_drugbank_similarity.si(compound_ids),
+            run_validate.si(compound_ids),
+        )
+        contribution_jobs.append(compounds_properties_computation_group)
+        # compounds_properties_computation_group.delay()
+    run_contribution_jobs = group(contribution_jobs)
+    workflow = chain(run_contribution_jobs, run_le_lle_plot.si(), run_pca_plot.si())
+    workflow.delay()
+
+
+def launch_plots_computing(self):
+    """
+    This task will perform the computing of LE-LLE and PCA plots.
+    """
+    workflow = chain(run_le_lle_plot.si(), run_pca_plot.si())
+    workflow.delay()
\ No newline at end of file
diff --git a/ippisite/ippisite/admin.py b/ippisite/ippisite/admin.py
index 77f66d97b3c8e505113e7bc1e170631b27bf405e..366e32dae4c977f5f717bd99fe5f5318c187ad14 100644
--- a/ippisite/ippisite/admin.py
+++ b/ippisite/ippisite/admin.py
@@ -3,8 +3,8 @@ from django.urls import path
 from django.shortcuts import redirect
 from django.contrib import messages
 from ippidb.tasks import (
-    launch_compound_properties_caching,
-    launch_drugbank_similarity_computing,
+    run_update_compound_cached_properties,
+    run_compute_drugbank_similarity,
     launch_plots_computing,
     launch_test_command_caching,
 )
@@ -53,7 +53,7 @@ class IppidbAdmin(admin.AdminSite):
         This view launches the task to perform, for all already validated compounds,
         the caching of the properties.
         """
-        launch_compound_properties_caching.delay()
+        run_update_compound_cached_properties.delay()
         messages.add_message(
             request, messages.INFO, "Compound properties caching launched"
         )
@@ -64,7 +64,7 @@ class IppidbAdmin(admin.AdminSite):
         This view launches the task to perform, for all already validated compounds,
         the computing of drugbank similarity.
         """
-        launch_drugbank_similarity_computing.delay()
+        run_compute_drugbank_similarity.delay()
         messages.add_message(
             request, messages.INFO, "DrugBank similarity computing launched"
         )