Há algumas semanas fiz uma entrevista, e um dos desafios era fazer o download de alguns arquivos em paralelo, e eu achei muito interessante, então resolvi fazer um artigo sobre isso. Falando um pouco do desafio, me foi fornecida a função pooledDownload que recebe uma lista de URLs, uma função connect que retorna uma conexão, o número máximo de conexões permitidas, e uma lista de URLs que devem ser baixadas e salvas; a ação deve ser feita em paralelo.
Critérios de aceitação
- Todos os arquivos devem ser baixados e salvos.
- O conteúdo do arquivo deve ser salvo assim que o arquivo for baixado.
- Downloads devem ser distribuídos igualmente entre as conexões.
- Uma conexão só pode baixar um arquivo por vez. Você deve criar mais conexões para baixar mais arquivos em paralelo.
- Qualquer conexão aberta deve ser fechada.
- Se não for possível abrir conexão com o servidor, você deve rejeitar com um
Error
contendo a mensagemConnection Failed
. - Se um erro ocorrer durante o download, você deve rejeitar com o mesmo erro.
- Às vezes o servidor pode não ter slots para lidar com o número de conexões simultâneas. Nesse caso, você deve parar a abertura de novas conexões quando o servidor alcançar o limite.
Solução
O primeiro passo que eu fiz foi criar a função getConnections
, ela recebe a função connect
e o número
máximo de conexões permitidas, e retorna um array de conexões abertas.
Eu sei que o break no catch, não é uma boa prática, mas é uma maneira simples de assegurar que estejamos em conformidade com o critério 8.
Agora que temos as conexões abertas, podemos implementar uma parte da função pooledDownload
.
A primeira ação que fiz foi criar uma cópia da lista de arquivos a serem baixados, e depois pegar o mínimo entre o
número de conexões permitidas e o número de arquivos a serem baixados, e então abrir as conexões. Se não for possível
abrir nenhuma conexão, eu rejeito a Promise com um Error
contendo a mensagem Connection Failed
.
Você pode se perguntar o porquê de usar o mínimo entre o número de conexões permitidas e o número de arquivos a serem baixados, isso é para garantir que não abriremos mais conexões do que o necessário.
O próximo passo é criar um loop que irá baixar os arquivos.
A função execute
é responsável por baixar os arquivos, e é onde a magia acontece.
O que acontece na função execute
é que eu verifico se ainda tem arquivos para serem baixados e se ainda tem
conexões abertas, se não tiver eu retorno uma promessa resolvida. Então eu pego o primeiro arquivo da lista de arquivos
a serem baixados, e a primeira conexão aberta, e então eu baixo o arquivo, salvo o conteúdo do arquivo, e então eu
coloco a conexão de volta no início do array de conexões, e chamo a função execute
novamente. Se um erro ocorrer
durante o download, eu coloco o arquivo de volta na lista de arquivos a serem baixados, e rejeito a promessa com o mesmo
erro.
Por fim, eu fecho as conexões.
Conclusão
Esse foi um desafio muito interessante, e eu gostei muito de fazer, eu aprendi muito, e espero que você também tenha aprendido. Se você tiver alguma dúvida, sugestão ou crítica, por favor mande uma mensagem, eu vou adorar ouvir o que você tem a dizer.
O resultado final fica assim: