First about timeouts:
set_time_limit() and max_execution_time don't count sleep(), system(), file_get_contents() and DB calls. That's why I thought the script ignores my limits.
I talked again to support and turned out that what stops the script is not Apache timeout but «something» that monitors scripts and stops it after 10 minutes for shared IP customers. I asked him for full list of limits:
Type | Dedicated | Shared -----------+-----------+----------- Apache/Web | 12 hours | 10 minutes SSH/Shell | 2 hours | 1 hour Cron Jobs | 1 hour | 30 minutes Daemons | Unlimited | 10 minutes
That's why it ran fine from the cron.