Repository: mindsdb/mindsdb

Issue:
Save predictor training time



Discussion:

Resolving patch:
diff --git a/mindsdb/interfaces/model/learn_process.py b/mindsdb/interfaces/model/learn_process.py
--- a/mindsdb/interfaces/model/learn_process.py
+++ b/mindsdb/interfaces/model/learn_process.py
@@ -7,6 +7,7 @@
 import json
 import requests
 import traceback
+from datetime import datetime
 
 import pandas as pd
 from pandas.core.frame import DataFrame
@@ -116,11 +117,11 @@ def run_fit(predictor_id: int, df: pd.DataFrame) -> None:
         config = Config()
 
         predictor_record.data = {'training_log': 'training'}
-        session.commit()
+        db.session.commit()
         predictor: lightwood.PredictorInterface = lightwood.predictor_from_code(predictor_record.code)
         predictor.learn(df)
 
-        session.refresh(predictor_record)
+        db.session.refresh(predictor_record)
 
         fs_name = f'predictor_{predictor_record.company_id}_{predictor_record.id}'
         pickle_path = os.path.join(config['paths']['predictors'], fs_name)
@@ -142,11 +143,11 @@ def run_fit(predictor_id: int, df: pd.DataFrame) -> None:
         predictor_record.data["submodel_data"] = submodel_data
 
         predictor_record.dtype_dict = predictor.dtype_dict
-        session.commit()
+        db.session.commit()
     except Exception as e:
-        session.refresh(predictor_record)
+        db.session.refresh(predictor_record)
         predictor_record.data = {'error': f'{traceback.format_exc()}\nMain error: {e}'}
-        session.commit()
+        db.session.commit()
         raise e
 
 
@@ -172,6 +173,11 @@ def run_learn(df: DataFrame, problem_definition: ProblemDefinition, predictor_id
               json_ai_override: dict = None) -> None:
     if json_ai_override is None:
         json_ai_override = {}
+
+    predictor_record = Predictor.query.with_for_update().get(predictor_id)
+    predictor_record.training_start_at = datetime.now()
+    db.session.commit()
+
     try:
         run_generate(df, problem_definition, predictor_id, json_ai_override)
         run_fit(predictor_id, df)
@@ -188,7 +194,10 @@ def run_learn(df: DataFrame, problem_definition: ProblemDefinition, predictor_id
             error_message = str(e)
 
         predictor_record.data = {"error": error_message}
-        session.commit()
+        db.session.commit()
+
+    predictor_record.training_stop_at = datetime.now()
+    db.session.commit()
 
 
 def run_adjust(name, db_name, from_data, datasource_id, company_id):
diff --git a/mindsdb/interfaces/storage/db.py b/mindsdb/interfaces/storage/db.py
--- a/mindsdb/interfaces/storage/db.py
+++ b/mindsdb/interfaces/storage/db.py
@@ -92,6 +92,8 @@ class Predictor(Base):
     update_status = Column(String, default='up_to_date')
     training_data_columns_count = Column(Integer)
     training_data_rows_count = Column(Integer)
+    training_start_at = Column(DateTime)
+    training_stop_at = Column(DateTime)
 
     json_ai = Column(Json, nullable=True)
     code = Column(String, nullable=True)
diff --git a/mindsdb/migrations/versions/2022-07-22_6e834843e7e9_training_time.py b/mindsdb/migrations/versions/2022-07-22_6e834843e7e9_training_time.py
new file mode 100644
--- /dev/null
+++ b/mindsdb/migrations/versions/2022-07-22_6e834843e7e9_training_time.py
@@ -0,0 +1,33 @@
+"""training_time
+
+Revision ID: 6e834843e7e9
+Revises: b5b53e0ea7f8
+Create Date: 2022-07-22 13:32:34.796604
+
+"""
+from alembic import op
+import sqlalchemy as sa
+import mindsdb.interfaces.storage.db
+
+
+# revision identifiers, used by Alembic.
+revision = '6e834843e7e9'
+down_revision = 'b5b53e0ea7f8'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    with op.batch_alter_table('predictor', schema=None) as batch_op:
+        batch_op.add_column(sa.Column('training_start_at', sa.DateTime(), nullable=True))
+        batch_op.add_column(sa.Column('training_stop_at', sa.DateTime(), nullable=True))
+    # ### end Alembic commands ###
+
+
+def downgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    with op.batch_alter_table('predictor', schema=None) as batch_op:
+        batch_op.drop_column('training_stop_at')
+        batch_op.drop_column('training_start_at')
+    # ### end Alembic commands ###


Test patch: