external objects retention time - #1
Conversation
dvdcastro
left a comment
There was a problem hiding this comment.
Thanks for working on this Kateryna. I've left some minor comments.
The task and the function changes will need unit tests written for them before we can submit to Catalyst.
| $currentpath = $this->get_external_path_from_hash($contenthash); | ||
| $this->externalclient->delete_file($currentpath); | ||
| $delay_delete_external_object = get_config('tool_objectfs', 'delaydeleteexternalobject'); | ||
| if($force_delay_delete) { |
There was a problem hiding this comment.
| if($force_delay_delete) { | |
| if ($force_delay_delete) { |
|
|
||
| $delay_objects_delete->id = $DB->insert_record('tool_objectfs_delay_delete', $delay_objects_delete, true); | ||
| } else { | ||
|
|
| $plugin->maturity = MATURITY_STABLE; | ||
| $plugin->supported = [310, 401]; | ||
| $plugin->dependencies = array( | ||
| 'local_aws' => 2022011300 |
There was a problem hiding this comment.
This is an optional dependency, we should not include it.
There was a problem hiding this comment.
This was already in the code. Should I just remove it then?
There was a problem hiding this comment.
Their version file does not have it. Yes, let's remove it.
https://github.com/catalyst/moodle-tool_objectfs/blob/MOODLE_310_STABLE/version.php
| $settings->add(new admin_setting_configcheckbox('tool_objectfs/preferexternal', | ||
| new lang_string('settings:preferexternal', 'tool_objectfs'), '', '')); | ||
|
|
||
| $settings->add(new admin_settings_aws_region('tool_objectfs/s3_region', |
There was a problem hiding this comment.
This also was already in the code. Not sure..
There was a problem hiding this comment.
It should not appear in the diff. I think you need to rebase your changes.
| $string['settings:batchsize_help'] = 'Number of files to be transferred in one cron run'; | ||
| $string['settings:maxorphanedage'] = 'Max orphaned object age'; | ||
| $string['settings:maxorphanedage_help'] = 'If set to zero, this will not delete old orphaned metadata for objects. Otherwise, it will remove these records as they are no longer relevant. An orphaned object is one where the metadata exists on the {tool_objectfs_objects} table but referenced file no longer exists.'; | ||
|
|
| * and external file (if delete external enabled) as it is no longer useful/relevant. | ||
| * | ||
| * @package tool_objectfs | ||
| * @author Kevin Pham <kevinpham@catalyst-au.net> |
There was a problem hiding this comment.
| * @author Kevin Pham <kevinpham@catalyst-au.net> | |
| * @author Katerina Martinenko <kateryna.martynenko@moodle.com> |
|
|
||
| $timeperiodforremoval = $this->config->delaydeleteexternalobject; | ||
| if (empty($timeperiodforremoval)) { | ||
| mtrace('Skipping delayed deletion of the external object of the delaydeleteexternalobject is set to an empty value.'); |
There was a problem hiding this comment.
What happens if there are files in the table still? Should we purge the table then?
There was a problem hiding this comment.
Right now the records are not deleting from the table, only updating. We could delete those directly from the table instead.
There was a problem hiding this comment.
Would that be okay keeping always an empty table though?
There was a problem hiding this comment.
We can purge the table as a last step. Let's say it purges files from the list which were removed 90 days ago. IDK what would happen if there was a file added that has the same content has and then also deleted. Would we have 2 entries in the table? If that's the case, and they don't clash, I don't see a problem with deleting these entries periodically. Deleting them straight away is also valid, you could get rid of the status field.
There was a problem hiding this comment.
Ok, I'll delete them directly then and will remove the status field.
| $objects = $DB->get_recordset_sql($sql, $params); | ||
| $count = 0; | ||
| foreach ($objects as $object) { | ||
|
|
| $deletedexternalobject->id = $object->id; | ||
| $deletedexternalobject->status = 1; | ||
| $DB->update_record('tool_objectfs_delay_delete', $deletedexternalobject); | ||
| $count++; |
There was a problem hiding this comment.
I think we should short circuit this for loop in case there are many files delayed to be deleted. Having a long list may harm the task execution for the entire site.
There was a problem hiding this comment.
Hmm good point! I can add a limit to that, for example, to delete 10 files at a time..?
There was a problem hiding this comment.
I think 1000 at a time is a good value.
There was a problem hiding this comment.
All right, will put a limit as 1000 :)
| $delay_delete_external_object = get_config('tool_objectfs', 'delaydeleteexternalobject'); | ||
| if($force_delay_delete) { | ||
| $this->externalclient->delete_file($currentpath); | ||
| } else if ($delay_delete_external_object > 0) { | ||
| $delay_objects_delete = new \stdClass(); | ||
| $delay_objects_delete->contenthash = $contenthash; | ||
| $delay_objects_delete->timecreated = time(); | ||
|
|
||
| $delay_objects_delete->id = $DB->insert_record('tool_objectfs_delay_delete', $delay_objects_delete, true); | ||
| } else { | ||
|
|
||
| $this->externalclient->delete_file($currentpath); | ||
| } |
There was a problem hiding this comment.
Minor suggestion.
| $delay_delete_external_object = get_config('tool_objectfs', 'delaydeleteexternalobject'); | |
| if($force_delay_delete) { | |
| $this->externalclient->delete_file($currentpath); | |
| } else if ($delay_delete_external_object > 0) { | |
| $delay_objects_delete = new \stdClass(); | |
| $delay_objects_delete->contenthash = $contenthash; | |
| $delay_objects_delete->timecreated = time(); | |
| $delay_objects_delete->id = $DB->insert_record('tool_objectfs_delay_delete', $delay_objects_delete, true); | |
| } else { | |
| $this->externalclient->delete_file($currentpath); | |
| } | |
| $delaydeleteexternalobject = get_config('tool_objectfs', 'delaydeleteexternalobject'); | |
| if($forcedelaydelete || $delaydeleteexternalobject <= 0) { | |
| $this->externalclient->delete_file($currentpath); | |
| } else if ($delaydeleteexternalobject > 0) { | |
| $delay_objects_delete = new \stdClass(); | |
| $delay_objects_delete->contenthash = $contenthash; | |
| $delay_objects_delete->timecreated = time(); | |
| $delay_objects_delete->id = $DB->insert_record('tool_objectfs_delay_delete', $delay_objects_delete, true); | |
| } |
| } | ||
|
|
||
| // If location change is 'orphaned' we update timeorphaned. | ||
| //Set time orphaned clock is ticking now for delay deletion comparison... |
There was a problem hiding this comment.
| //Set time orphaned clock is ticking now for delay deletion comparison... | |
| // Set time orphaned clock is ticking now for delay deletion comparison... |
| * Deletes external file depending on deleteexternal settings. | ||
| * | ||
| * @param string $contenthash file to be moved | ||
| * @param boolean $forcedelete will force to delete the file |
There was a problem hiding this comment.
| * @param boolean $forcedelete will force to delete the file |
| global $DB; | ||
|
|
| 'minute' => '*', | ||
| 'hour' => '*', |
There was a problem hiding this comment.
I think we can run this in the same manner as the tool_objectfs\task\orphan_objects and the tool_objectfs\task\delete_orphaned_object_metadata tasks. This is optional, just an opinion.
| 'minute' => '*', | |
| 'hour' => '*', | |
| 'minute' => 'R', | |
| 'hour' => 'R', |
| $string['settings:batchsize_help'] = 'Number of files to be transferred in one cron run'; | ||
| $string['settings:maxorphanedage'] = 'Max orphaned object age'; | ||
| $string['settings:maxorphanedage_help'] = 'If set to zero, this will not delete old orphaned metadata for objects. Otherwise, it will remove these records as they are no longer relevant. An orphaned object is one where the metadata exists on the {tool_objectfs_objects} table but referenced file no longer exists.'; | ||
|
|
| $this->assertTrue($this->is_externally_readable_by_hash($filehash)); | ||
| } | ||
|
|
||
| public function presigned_url_should_redirect_provider() { |
| * | ||
| * @return array | ||
| */ | ||
| public function get_expiration_time_method_if_supported_provider() { |
| * | ||
| * @return array | ||
| */ | ||
| public function get_valid_http_ranges_provider() { |
| * | ||
| * @return array | ||
| */ | ||
| public function curl_range_request_to_presigned_url_provider() { |
| /** | ||
| * Execute task | ||
| */ | ||
| public function execute() { |
There was a problem hiding this comment.
I don't understand this test. How is it validating that elements are being deleted from the external system? I think we should create mocks for the method $filesystem->delete_external_file_from_hash(...), and check that when the task is run, the method is called under the correct circumstances.
dvdcastro
left a comment
There was a problem hiding this comment.
Thanks for working on this Kateryna. Please review the comments I had left in prior reviews where I suggested removing empty lines or whitespaces, they still have not been addressed.
|
|
||
| manager::update_object($objectrecord, OBJECT_LOCATION_ORPHANED); | ||
|
|
||
| $this->assertTrue($this->is_externally_readable_by_hash($filehash)); |
There was a problem hiding this comment.
I suggest we also validate that the objectfs row has the timeorphaned value set.
$objectrecord = $DB->get_record('tool_objectfs_objects', ['contenthash' => $filehash]);
$this->assertGreaterThan($objectrecord->timeorphaned, 0, 'Time orphaned should be greater than 0.');| $this->assertTrue($this->is_externally_readable_by_hash($filehash)); | ||
| } | ||
|
|
||
| public function test_if_external_orphaned_object_is_deleted_after_delaydeleteexternalobject_setting() { |
There was a problem hiding this comment.
This method is not currently testing something. I suggest we delete it. If you want to test the task execution, I suggest you first create orphaned files with an expired orphanedtime and then run the execute function from the task.
There was a problem hiding this comment.
But I think we can get a pass on running tests for the task. They are currently not testing their tasks.
No description provided.