I've managed to fix the problem using some inspiration I've got from how-can-i-clean-up-the-ssisdb
Supposedly the real issue is that cascading deletes don't occur.
I've used below approach to reduce the database size by more than 1GB after the default cleanup procedure.
1: First run the default cleanup procedure
EXEC [internal].[cleanup_server_retention_window]
2: Check the table sizes
SELECT
s.[name] AS [Schema],
t.[name] AS [Table],
p.[rows] AS [Rows],
SUM(a.[total_pages]) * 8 / 1024 AS [TotalMB],
SUM(a.[used_pages]) * 8 / 1024 AS [UsedMB],
(SUM(a.[total_pages]) - SUM(a.[used_pages])) * 8 / 1024 AS [UnusedMB]
FROM sys.tables t
INNER JOIN sys.schemas s ON s.schema_id = t.schema_id
INNER JOIN sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN sys.allocation_units a ON p.partition_id = a.container_id
WHERE t.[name] NOT LIKE 'dt%' AND t.[is_ms_shipped] = 0 AND i.[object_id] > 255
GROUP BY t.[name], s.[name], p.[rows]
ORDER BY p.[rows] desc, s.[name], t.[name]
3: Execute manual delete of obsolete operation_id's.
I've shamelessly 'stolen' and then adjusted the code from the stackoverflow post.
First step is creating temp table with a list of all the operation_id's I would like to keep (I've set retention days to 30).
Next delete all the operation_id's that are not within the temp table. (I've checked for all the tables that have a operation_id column and records).
IF object_id('tempdb..#KEEP_CANDIDATES') IS NOT NULL
BEGIN
DROP TABLE #KEEP_CANDIDATES;
END;
-- Populate temp table with operation id you like to keep
CREATE TABLE #KEEP_CANDIDATES ( operation_id bigint NOT NULL PRIMARY KEY);
DECLARE @DaysRetention int = 30; --Set the retention days
INSERT INTO #KEEP_CANDIDATES (operation_id )
SELECT IO.operation_id
FROM internal.operations AS IO
WHERE IO.start_time >= DATEADD(day, -@DaysRetention, CURRENT_TIMESTAMP);
-- Delete the records for operation id you dont want to keep
DELETE T
FROM internal.event_message_context_scaleout AS T
LEFT JOIN #KEEP_CANDIDATES AS DC ON DC.operation_id = T.operation_id
WHERE DC.operation_id IS NULL;
DELETE T
FROM internal.event_messages_scaleout AS T
LEFT JOIN #KEEP_CANDIDATES AS DC ON DC.operation_id = T.operation_id
WHERE DC.operation_id IS NULL;
DELETE T
FROM internal.operation_messages_scaleout AS T
LEFT JOIN #KEEP_CANDIDATES AS DC ON DC.operation_id = T.operation_id
WHERE DC.operation_id IS NULL;
-- Finally, remove the entry from operations
DELETE T
FROM internal.operations AS T
LEFT JOIN #KEEP_CANDIDATES AS DC ON DC.operation_id = T.operation_id
WHERE DC.operation_id IS NULL;
4: Rebuild indexes to reclaim space
ALTER INDEX ALL ON internal.event_message_context_scaleout REBUILD;
ALTER INDEX ALL ON internal.event_messages_scaleout REBUILD;
ALTER INDEX ALL ON internal.operation_messages_scaleout REBUILD;
ALTER INDEX ALL ON internal.operations REBUILD;
5: Repeat step 2 and validate results.
Happy times!