Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
231 views
in Technique[技术] by (71.8m points)

multithreading - C# DBContext doesn't exist after executing some long tasks

First of all I have to say that I'm not sure if I'm coding the proper approach, I'll first explain what I'm trying to do.

  1. Receive POST request to create a new RawTask.
  2. Insert the RawTask in its DB table and a related register in ProcessedTask table.
  3. Execute some long tasks (inside Thread.Task)
  4. Update the ProcessedTask with the feedback of the previous point.

Doubts/Problems

  1. The first problem is that the DBContext doesn't exist when the task finishes its execution. So it's impossible to update the processedTask.
  2. The insertedTask.ExecuteScript() is well placed at TaskController/POST method?
  3. Is it a good approach to create and update the ProcessedTask entity in the POST method of this Task Controller?

Here's some code to explain it better.

public class RawTaskController : ControllerBase
        {
            private readonly ICrudService<RawTask> _rawTaskCrudService;

            private readonly ICrudService<ProcessedTask> _processedTaskCrudService;

            public RawTaskController(ICrudService<RawTask> taskCrudService, ICrudService<ProcessedTask> processedTaskCrudService)
            {
                _rawTaskCrudService = taskCrudService;
                _processedTaskCrudService = processedTaskCrudService;
            }

            [HttpPost]
            public async Task<IActionResult> AddTask([FromBody] RawTaskModel rawTask)
            {
                insertedRawTask insertedRawTask;
                ProcessedTask processedTask = new ProcessedTask();

                try
                {
                    //Initialize some fields
                    rawTask.Id = Guid.NewGuid();
                    rawTask.DateReg = DateTime.Now;

                    //Insert the received task after mapping the model.
                    insertedRawTask = await _rawTaskCrudService.Add(rawTaskMapper.Map(rawTask));



                    if (insertedRawTask != null)
                    {
                        //Initializing the new processedTask
                        processedTask.Id = Guid.NewGuid();
                        processedTask.IdRawTask = insertedRawTask.Id;
                        processedTask.DateReg = DateTime.Now;
                    }

                    //Insert the processedTask after getting some fields from RawTask.
                    ProcessedTask insertedProcessedTask = await _processedTaskCrudService.Add(processedTask);


                    if (insertedProcessedTask != null)
                    {
                        //Here comes the long executiong, for example a HDD defrag (some hours)   
                        Task task = new Task(async () =>
                        {
                        //The behaviour of the execution is defined in the domain class Task
                        if (insertedRawTask.ExecuteScript())
                            {
                            //If the execution was succesful we will update the processedTask created before
                            insertedProcessedTask.State = "Finished";
                                await _processedTaskCrudService.Update(insertedProcessedTask);
                            }
                        });
                        task.Start();
                    }
                    else
                    {
                        return StatusCode(500);
                    }
                }
                catch (Exception)
                {
                    return StatusCode(500);
                }
                return Ok(insertedRawTask);
            }
        }

I would appreciate any other possible solutions to accomplish this kind of behavior. Thanks in advance.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Request-extrinsic code is dangerous; a proper solution is to use a durable queue with a background processor. There are very few scenarios where just throwing a task on the thread pool is an appropriate solution.

The first problem is that the DBContext doesn't exist when the task finishes its execution. So it's impossible to update the processedTask.

Background processors need their own DbContext.

I generally recommend the background processor be a completely separate process - Azure Function, Win32 Service, etc.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...